/* Web Terminal — modern dark UI */ :root { /* palette (design tokens) — Amber 琥珀金 theme (warm-neutral base + gold accent) */ --bg: #100f0d; /* terminal / deepest surface — warm near-neutral */ --surface-1: #181613; /* tab bar, key bar */ --surface-2: #1f1c17; /* tabs, buttons, cards */ --surface-3: #2a2620; /* hover / active */ --border: rgba(255, 255, 255, 0.07); --border-strong: rgba(255, 255, 255, 0.14); --text: #ece9e3; --text-dim: #a8a299; --text-faint: #6f6a61; --accent: #e3a64a; /* amber gold */ --accent-2: #c9892f; /* deeper gold (gradients / hover) */ --accent-soft: rgba(227, 166, 74, 0.15); --on-accent: #1a1305; /* text/icon color on a gold accent background (contrast) */ --green: #46d07f; /* connection-status: connected */ --amber: #f5b14c; /* connection-status: connecting */ --red: #ff6b6b; /* connection-status: disconnected / error */ --shadow: 0 10px 40px rgba(0, 0, 0, 0.55); --radius: 9px; --radius-lg: 14px; --tabbar-h: 40px; --keybar-h: 46px; /* iOS notch / home-indicator clearance. index.html sets viewport-fit=cover, * so the layout spans the physical screen edges; without these the top bar * hides under the status bar and the bottom key-bar covers terminal output. * Falls back to 0px on platforms without safe areas. */ --safe-t: env(safe-area-inset-top, 0px); --safe-b: env(safe-area-inset-bottom, 0px); --ui-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; } @media (pointer: coarse) { :root { --tabbar-h: 48px; --keybar-h: 60px; } } html, body { margin: 0; padding: 0; width: 100%; height: 100%; background-color: var(--bg); color: var(--text); font-family: var(--ui-font); overflow: hidden; } * { scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent; } /* ── Tab bar ─────────────────────────────────────────────────────── */ #tabbar { position: fixed; inset: 0 0 auto 0; box-sizing: border-box; height: calc(var(--tabbar-h) + var(--safe-t)); padding-top: var(--safe-t); background: linear-gradient(180deg, #181a22, var(--surface-1)); border-bottom: 1px solid var(--border); display: flex; align-items: stretch; z-index: 1001; } #tabs { flex: 1 1 auto; display: flex; align-items: center; gap: 2px; padding: 0 4px; overflow-x: auto; overflow-y: hidden; } #tabs::-webkit-scrollbar { height: 0; } /* tabs as floating rounded chips */ .tab { display: flex; align-items: center; gap: 2px; height: calc(var(--tabbar-h) - 12px); padding: 0 4px 0 10px; border-radius: 8px; color: var(--text-dim); background: transparent; cursor: pointer; white-space: nowrap; font-size: 13px; user-select: none; max-width: 220px; transition: background 0.12s ease, color 0.12s ease; } .tab:hover { background: var(--surface-2); color: var(--text); } .tab.active { background: var(--surface-3); color: #fff; box-shadow: inset 0 0 0 1px var(--border-strong); } .tab-dot { width: 7px; height: 7px; border-radius: 50%; margin-right: 8px; flex: none; background: var(--text-faint); } .dot-connected { background: var(--green); box-shadow: 0 0 6px rgba(70, 208, 127, 0.5); } .dot-connecting, .dot-reconnecting { background: var(--amber); } .dot-exited { background: var(--red); } .tab-label { padding-right: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tab-rename { width: 120px; margin: 0 4px; padding: 3px 6px; font: inherit; font-size: 13px; color: #fff; background: var(--bg); border: 1px solid var(--accent); border-radius: 6px; outline: none; } /* unread / Claude-waiting accents */ .tab.unread .tab-dot { box-shadow: 0 0 0 3px var(--accent-soft); } .tab.unread .tab-label { color: #fff; font-weight: 600; } .tab-claude { margin-right: 4px; font-size: 12px; flex: none; } .tab.claude-waiting { background: rgba(245, 177, 76, 0.14); box-shadow: inset 0 0 0 1px rgba(245, 177, 76, 0.5); } .tab.dragging { opacity: 0.4; } .tab.drag-over { box-shadow: inset 3px 0 0 var(--accent); } .tab-close { background: none; border: none; color: var(--text-faint); cursor: pointer; font-size: 16px; line-height: 1; padding: 3px 6px; border-radius: 6px; flex: none; } .tab-close:hover { background: rgba(255, 255, 255, 0.1); color: #fff; } @media (pointer: fine) { .tab:not(.active):not(:hover) .tab-close { opacity: 0; } } .tab-add { background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 18px; padding: 0 10px; flex: none; border-radius: 7px; } .tab-add:hover { color: #fff; background: var(--surface-2); } /* v0.6: Home (⌂) button — opens the Sessions/Projects chooser over open tabs. */ .tab-home { background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 17px; padding: 0 10px; flex: none; border-radius: 7px; } .tab-home:hover { color: #fff; background: var(--surface-2); } .tab-home.active { color: var(--on-accent, #1a1408); background: var(--accent); } /* toolbar */ #toolbar { flex: 0 0 auto; display: flex; align-items: center; gap: 2px; padding: 0 6px; border-left: 1px solid var(--border); } .toolbtn { position: relative; /* for the hover tooltip */ display: inline-flex; align-items: center; justify-content: center; background: none; border: none; color: var(--text-dim); cursor: pointer; padding: 7px 9px; border-radius: 8px; line-height: 1; transition: background 0.12s ease, color 0.12s ease; } .toolbtn svg { display: block; width: 18px; height: 18px; } .toolbtn:hover { color: var(--accent); background: var(--surface-2); } /* Hover tooltip (right-anchored so it never clips the screen edge). */ .toolbtn[data-tip]::after { content: attr(data-tip); position: absolute; top: calc(100% + 6px); right: 0; white-space: nowrap; background: var(--surface-3); color: var(--text); border: 1px solid var(--border-strong); padding: 4px 8px; border-radius: 6px; font-size: 12px; font-weight: 500; opacity: 0; pointer-events: none; transition: opacity 0.12s ease; z-index: 60; } .toolbtn[data-tip]:hover::after { opacity: 1; } /* ── Terminal area ───────────────────────────────────────────────── */ #term { position: absolute; inset: calc(var(--tabbar-h) + var(--safe-t)) 0 calc(var(--keybar-h) + var(--safe-b)) 0; background: var(--bg); overflow: hidden; } /* Each pane lives in a .term-cell wrapper (header + terminal + optional inline * approve). In single mode the cell fills #term absolutely (only the focused one * is shown) so the classic one-pane look is unchanged; split layouts turn #term * into a CSS grid and the cells flow into tracks. */ .term-cell { position: absolute; inset: 0; display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; } .term-pane { position: relative; flex: 1 1 auto; min-height: 0; padding: 6px 8px 0; box-sizing: border-box; overflow: hidden; } /* Cell header + inline-approve footer are hidden in single mode. */ .cell-head, .cell-approve { display: none; } /* ── Split-grid layouts (desktop watch board) ────────────────────────── */ /* Shared cell chrome keys off the single `grid` marker so it is independent of * how many concrete layouts exist; each `lay-*` only sets the grid template. */ #term.grid { display: grid; gap: 6px; padding: 6px; } #term.lay-split-2 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr; } #term.lay-row-3 { grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr; } #term.lay-grid-4 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } #term.lay-grid-6 { grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr; } #term.grid .term-cell { position: relative; inset: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); } /* Keep the last terminal row clear of the cell border/focus ring in a grid. * Root cause (measured): the base .term-pane is box-sizing:border-box, so * getComputedStyle(pane).height — which xterm's FitAddon reads to compute rows — * returns the PADDING-box height and double-counts the pane's own padding, packing * one extra row that overruns into the border (overflow +6px). content-box makes * that height report the CONTENT box, so FitAddon drops the phantom row and the 6px * padding becomes real clearance. (Single mode keeps padding 0 so the terminal * still fills to the key-bar.) */ #term.grid .term-pane { box-sizing: content-box; padding-bottom: 6px; } /* Maximized quadrant fills the whole grid as an ABSOLUTE overlay (taken out of * grid flow so the siblings keep their placement — spanning grid tracks instead * would shove auto-placed siblings into implicit rows, resizing their live PTYs). * #term is a positioned containing block, so inset:0 covers the whole area. */ #term.grid .term-cell.maximized { position: absolute; inset: 0; z-index: 4; } /* A tab dragged from the tab bar is hovering this quadrant. */ #term.grid .term-cell.drag-target { outline: 2px dashed var(--accent); outline-offset: -3px; } /* Draggable splitter handles overlaying the track boundaries (v3). */ .grid-gutter { position: absolute; z-index: 3; touch-action: none; } .grid-gutter::after { content: ''; position: absolute; background: var(--border-strong); border-radius: 2px; opacity: 0; transition: opacity 0.15s; } .grid-gutter:hover::after, .grid-gutter:active::after { opacity: 1; background: var(--accent); } .grid-gutter-col { top: 0; bottom: 0; width: 12px; transform: translateX(-50%); cursor: col-resize; } .grid-gutter-col::after { top: 15%; bottom: 15%; left: 50%; width: 3px; transform: translateX(-50%); } .grid-gutter-row { left: 0; right: 0; height: 12px; transform: translateY(-50%); cursor: row-resize; } .grid-gutter-row::after { left: 15%; right: 15%; top: 50%; height: 3px; transform: translateY(-50%); } #term.grid .cell-head { display: flex; align-items: center; gap: 8px; padding: 5px 9px; background: linear-gradient(180deg, var(--surface-2), var(--surface-1)); border-bottom: 1px solid var(--border); font-size: 12px; cursor: pointer; user-select: none; } .cell-max { border: 0; background: transparent; color: var(--text-faint); cursor: pointer; font-size: 13px; line-height: 1; padding: 2px 4px; border-radius: 5px; } .cell-max:hover { color: var(--text); background: var(--surface-3); } .cell-keep { border: 0; background: transparent; color: var(--text-faint); cursor: pointer; font-size: 13px; line-height: 1; padding: 2px 4px; border-radius: 5px; } .cell-keep:hover { color: var(--text); background: var(--surface-3); } .cell-monitor-btn { border: 0; background: transparent; color: var(--text-faint); cursor: pointer; font-size: 12px; line-height: 1; padding: 2px 4px; border-radius: 5px; opacity: 0.7; } .cell-monitor-btn:hover { color: var(--text); background: var(--surface-3); opacity: 1; } .cell-monitor-btn.active { color: var(--accent); opacity: 1; } /* Read-only monitor preview fills the cell below the header. */ .cell-monitor { flex: 1 1 auto; min-height: 0; overflow: hidden; position: relative; padding: 6px 8px 0; box-sizing: border-box; } .cell-name { font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .cell-status { margin-left: auto; font-size: 11px; color: var(--text-dim); white-space: nowrap; } .cell-status.cs-working { color: var(--amber); } .cell-status.cs-waiting { color: var(--accent); } .cell-status.cs-idle { color: var(--green); } .cell-status.cs-stuck { color: var(--red); } /* Focus ring — the quadrant that owns keyboard / keybar / voice / approvals. */ #term.grid .term-cell.focused { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), var(--shadow); } /* Pending glow — a non-focused quadrant is waiting for approval. */ #term.grid .term-cell.pending:not(.focused) { border-color: var(--amber); animation: cell-pending 2.4s ease-in-out infinite; } @keyframes cell-pending { 0%, 100% { box-shadow: 0 0 0 1px rgba(245, 177, 76, 0.35); } 50% { box-shadow: 0 0 0 1px rgba(245, 177, 76, 0.7), 0 0 26px -8px rgba(245, 177, 76, 0.6); } } @media (prefers-reduced-motion: reduce) { #term.grid .term-cell.pending { animation: none; } } /* Inline per-quadrant approve footer. */ #term.grid .cell-approve { display: flex; align-items: center; gap: 8px; padding: 6px 9px; background: rgba(245, 177, 76, 0.08); border-top: 1px solid rgba(245, 177, 76, 0.35); font-size: 11.5px; } .cell-approve-label { color: var(--amber); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .cell-approve-btns { margin-left: auto; display: flex; gap: 6px; } .cell-approve-yes, .cell-approve-no { border: 0; border-radius: 6px; padding: 3px 11px; font-size: 12px; font-weight: 600; cursor: pointer; } .cell-approve-yes { background: var(--green); color: #06231a; } .cell-approve-no { background: var(--surface-3); color: var(--text-dim); } .cell-approve-yes:hover { filter: brightness(1.1); } .cell-approve-no:hover { color: var(--text); } /* Empty-slot placeholder (fewer sessions than the layout holds). */ .term-cell.slot-empty { border: 1px dashed var(--border-strong); background: repeating-linear-gradient( -45deg, transparent, transparent 10px, rgba(255, 255, 255, 0.02) 10px, rgba(255, 255, 255, 0.02) 20px ); align-items: center; justify-content: center; cursor: pointer; } .term-cell.slot-empty:hover { border-color: var(--accent); } .slot-new { display: flex; flex-direction: column; align-items: center; gap: 6px; background: none; border: 0; color: var(--text-faint); font-size: 12px; font-family: var(--ui-font); cursor: pointer; } .slot-new b { font-size: 26px; font-weight: 300; line-height: 1; color: var(--text-dim); } .term-cell.slot-empty:hover .slot-new { color: var(--text-dim); } /* ── Grid-toggle segmented control (toolbar) ─────────────────────────── */ .grid-toggle { display: inline-flex; align-items: center; gap: 2px; margin-left: 4px; padding: 2px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; } .grid-toggle-btn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 26px; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--text-faint); cursor: pointer; } .grid-toggle-btn:hover { color: var(--text); background: var(--surface-3); } .grid-toggle-btn[aria-pressed='true'] { color: var(--on-accent); background: var(--accent); } .grid-glyph { display: grid; gap: 1.5px; width: 14px; height: 12px; } .grid-glyph.gl-single { grid-template-columns: 1fr; } .grid-glyph.gl-split-2 { grid-template-columns: 1fr 1fr; } .grid-glyph.gl-row-3 { grid-template-columns: 1fr 1fr 1fr; } .grid-glyph.gl-grid-4 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } .grid-glyph.gl-grid-6 { grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr; } .grid-glyph i { background: currentColor; border-radius: 1px; } /* Touch tablets clear the 1024px width gate but need bigger tap targets — mirror * the project's existing coarse-pointer bump for the tab/key bars. */ @media (pointer: coarse) { .grid-toggle { gap: 3px; } .grid-toggle-btn { width: 36px; height: 34px; } .cell-max, .cell-monitor-btn { padding: 6px 9px; font-size: 15px; } } /* ── Key bar (rounded chips) ─────────────────────────────────────── */ #keybar { position: fixed; inset: auto 0 0 0; box-sizing: border-box; height: calc(var(--keybar-h) + var(--safe-b)); background: var(--surface-1); border-top: 1px solid var(--border); display: flex; align-items: center; gap: 5px; padding: 0 6px var(--safe-b); overflow-x: auto; overflow-y: hidden; z-index: 1000; } #keybar::-webkit-scrollbar { height: 0; } #keybar button { flex: 1 0 auto; min-width: 50px; height: calc(var(--keybar-h) - 12px); padding: 0 10px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); font-family: var(--ui-font); cursor: pointer; border-radius: 8px; transition: background 0.1s ease, transform 0.05s ease; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; } #keybar .kb-key { font-size: 13px; line-height: 1.1; } #keybar .kb-cap { font-size: 9px; line-height: 1; color: var(--text-faint); letter-spacing: 0.02em; } #keybar button:hover { background: var(--surface-3); } #keybar button:active { transform: translateY(1px); background: var(--surface-3); } #keybar button.keybar-btn-primary { background: var(--accent-soft); color: #f0d49a; border-color: rgba(227, 166, 74, 0.4); font-weight: 600; min-width: 54px; } #keybar button.keybar-btn-primary:hover { background: rgba(227, 166, 74, 0.26); } #keybar button.keybar-btn-primary .kb-cap { color: rgba(240, 212, 154, 0.7); } /* ── Shared: overlays, cards, inputs, buttons ────────────────────── */ .overlay { position: fixed; inset: 0; z-index: 1200; display: flex; background: rgba(8, 9, 12, 0.6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); } #searchbox { position: fixed; top: calc(var(--tabbar-h) + var(--safe-t) + 8px); right: 10px; z-index: 1100; display: flex; gap: 5px; padding: 7px; background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 10px; box-shadow: var(--shadow); } .search-input { width: 190px; padding: 5px 8px; font: inherit; font-size: 13px; color: #fff; background: var(--bg); border: 1px solid var(--border); border-radius: 7px; outline: none; } .search-input:focus { border-color: var(--accent); } #searchbox button { background: var(--surface-3); border: 1px solid var(--border); color: var(--text); cursor: pointer; border-radius: 7px; padding: 0 10px; } #searchbox button:hover { background: var(--accent-soft); } /* QR + share modals */ #qrmodal, #sharemodal { position: fixed; inset: 0; z-index: 1200; display: flex; align-items: center; justify-content: center; background: rgba(8, 9, 12, 0.6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); } .qr-card { background: var(--surface-2); color: var(--text); border: 1px solid var(--border-strong); border-radius: var(--radius-lg); padding: 22px; text-align: center; max-width: 90vw; box-shadow: var(--shadow); } .qr-card canvas { border-radius: 10px; background: #fff; padding: 8px; } .qr-title { font-weight: 600; margin-bottom: 14px; } .qr-url { margin-top: 12px; font-size: 13px; color: var(--accent); word-break: break-all; } .qr-note { margin-top: 8px; font-size: 12px; color: var(--text-dim); max-width: 240px; } .qr-close { margin-top: 16px; padding: 8px 20px; border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface-3); color: #fff; cursor: pointer; font: inherit; } .qr-close:hover { background: var(--accent-soft); } /* Settings panel */ #settingspanel { position: fixed; top: calc(var(--tabbar-h) + var(--safe-t) + 8px); right: 10px; z-index: 1100; background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 12px; padding: 12px; min-width: 220px; box-shadow: var(--shadow); color: var(--text); } .settings-row { display: flex; align-items: center; gap: 6px; margin: 8px 0; } .settings-label { width: 48px; color: var(--text-dim); font-size: 13px; } .settings-opt { background: var(--surface-3); border: 1px solid var(--border); color: var(--text); border-radius: 7px; padding: 5px 10px; cursor: pointer; font: inherit; font-size: 12px; transition: background 0.1s ease; } .settings-opt:hover { background: var(--surface-1); } .settings-opt.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); } .settings-size { min-width: 22px; text-align: center; } /* Dashboard + history + shortcuts share the centered-card look */ #dashboard, #historymodal, #shortcutsmodal { position: fixed; inset: 0; z-index: 1200; display: flex; align-items: flex-start; justify-content: center; padding-top: 60px; background: rgba(8, 9, 12, 0.6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); } .dash-card, .hist-card, .sc-card { background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: var(--radius-lg); min-width: 340px; max-width: 92vw; max-height: 72vh; overflow-y: auto; box-shadow: var(--shadow); } .sc-card { width: 540px; } .dash-title, .hist-title, .sc-title { padding: 14px 18px; font-weight: 600; color: #fff; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--surface-2); } /* Shortcut cheat-sheet */ .sc-group { padding: 12px 18px 4px; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent); } .sc-row { display: flex; align-items: center; gap: 12px; padding: 6px 18px; } .sc-key { flex: none; min-width: 110px; font-family: Menlo, Consolas, monospace; font-size: 12px; color: #fff; background: var(--bg); border: 1px solid var(--border-strong); border-radius: 6px; padding: 3px 8px; text-align: center; } .sc-desc { flex: 1 1 auto; color: var(--text-dim); font-size: 13px; } .sc-tag { flex: none; font-size: 10px; color: var(--accent); background: var(--accent-soft); border-radius: 5px; padding: 2px 6px; } .dash-row, .hist-row { display: flex; align-items: center; gap: 10px; padding: 11px 18px; cursor: pointer; color: var(--text); border-bottom: 1px solid var(--border); transition: background 0.1s ease; } .dash-row:hover, .hist-row:hover { background: var(--surface-3); } .dash-row.active { box-shadow: inset 3px 0 0 var(--accent); } .dash-name { flex: 1; } .dash-claude { color: var(--text-dim); font-size: 13px; } .dash-claude.pending { color: var(--amber); font-weight: 600; } .hist-empty { padding: 18px; color: var(--text-dim); } .hist-row { cursor: default; } .hist-main { flex: 1 1 auto; min-width: 0; } .hist-proj { color: #fff; font-size: 13px; } .hist-prev { color: var(--text-dim); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .hist-resume { flex: none; background: var(--accent); color: var(--on-accent); border: none; border-radius: 8px; padding: 7px 15px; cursor: pointer; font: inherit; font-weight: 500; transition: background 0.1s ease; } .hist-resume:hover { background: var(--accent-2); } /* Approval banner (H3) */ #approvalbar { position: fixed; inset: auto 0 calc(var(--keybar-h) + var(--safe-b)) 0; z-index: 1050; display: flex; flex-wrap: wrap; /* W1: a preview row wraps below the label + buttons */ align-items: center; gap: 10px; padding: 10px 14px; background: linear-gradient(180deg, rgba(245, 177, 76, 0.16), rgba(245, 177, 76, 0.08)); border-top: 1px solid rgba(245, 177, 76, 0.5); color: #ffe0ad; font-size: 14px; } .approval-label { flex: 1 1 auto; } /* W1: approval preview (command/diff) — its own full-width row, scrollable. */ .approval-preview { flex: 1 1 100%; order: 3; /* below the label + buttons regardless of insertion order */ max-height: 30vh; overflow: auto; overflow-x: auto; border: 1px solid rgba(245, 177, 76, 0.35); border-radius: 8px; background: rgba(0, 0, 0, 0.35); padding: 8px 10px; } .approval-cmd { margin: 0; white-space: pre-wrap; word-break: break-word; font-family: Menlo, Consolas, monospace; font-size: 13px; color: #f4f5f7; } .approval-truncated { margin-top: 6px; font-size: 12px; opacity: 0.7; } #approvalbar button { flex: none; border: none; border-radius: 8px; padding: 8px 16px; cursor: pointer; font: inherit; font-weight: 600; } .approval-yes { background: var(--green); color: #06210f; } .approval-no { background: var(--red); color: #2a0808; } /* ── Launcher (home session chooser, shown when no tab is open) ──── */ .launcher { position: absolute; inset: 52px 0 0 0; /* mobile: reserve a row for the stacked .home-seg (desktop overrides to 0) */ overflow-y: auto; padding: 22px 18px 40px; box-sizing: border-box; background: var(--bg); } .launcher-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 16px; margin-bottom: 18px; } .launcher-title { font-size: 20px; font-weight: 700; color: #fff; } .launcher-sub { flex: 1 1 auto; color: var(--text-dim); font-size: 13px; } .launcher-actions { display: flex; gap: 8px; } /* "New session" tile — leads the session grid, matching the session cards. */ .mg-new-card { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; min-height: 200px; background: none; border: 2px dashed var(--border-strong); border-radius: 12px; color: var(--text-dim); cursor: pointer; font: inherit; transition: border-color 0.12s ease, color 0.12s ease, background 0.12s ease; } .mg-new-card:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); } .mg-new-plus { font-size: 34px; font-weight: 300; line-height: 1; } .mg-new-label { font-size: 14px; font-weight: 600; } /* ── Session Manager page (manage.html) ──────────────────────────── */ #manage-root { max-width: 1200px; margin: 0 auto; padding: 24px 16px 60px; height: 100%; overflow-y: auto; box-sizing: border-box; } .mg-header { margin-bottom: 18px; } .mg-title { font-size: 22px; font-weight: 700; color: #fff; } .mg-sub { color: var(--text-dim); font-size: 13px; margin-top: 2px; } .mg-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; } .mg-btn { background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text); border-radius: 8px; padding: 8px 14px; cursor: pointer; font: inherit; font-size: 13px; text-decoration: none; transition: background 0.1s ease; } .mg-btn:hover { background: var(--surface-3); } .mg-btn.warn { border-color: rgba(245, 177, 76, 0.5); color: var(--amber); } .mg-btn.danger { border-color: rgba(255, 107, 107, 0.5); color: var(--red); } .mg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 14px; } .mg-card { display: flex; flex-direction: column; gap: 10px; padding: 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; } .mg-card-head { display: flex; align-items: center; gap: 8px; } .mg-name { flex: 1 1 auto; min-width: 0; color: #fff; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Live preview thumbnail (scaled read-only xterm) */ .mg-thumb { position: relative; width: 100%; min-height: 90px; background: #0e0f13; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; cursor: pointer; } .mg-thumb:hover { border-color: var(--accent); } .mg-thumb-inner { position: absolute; top: 0; left: 0; transform-origin: top left; padding: 4px; } .mg-watch { font-size: 11px; color: var(--text-faint); background: var(--surface-3); border-radius: 5px; padding: 1px 6px; } .mg-watch.live { color: var(--green); background: rgba(70, 208, 127, 0.14); } .mg-status { font-size: 11px; color: var(--text-dim); } .mg-status.mg-waiting { color: var(--amber); font-weight: 600; } .mg-status.mg-working { color: var(--accent); } .mg-meta { color: var(--text-faint); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: Menlo, Consolas, monospace; } .mg-actions { display: flex; gap: 6px; } .mg-actions .mg-open { flex: 1 1 auto; text-align: center; } .mg-open { background: var(--accent); color: var(--on-accent); border-radius: 8px; padding: 7px 13px; text-decoration: none; font-size: 13px; } .mg-open:hover { background: var(--accent-2); } .mg-kill { background: transparent; border: 1px solid rgba(255, 107, 107, 0.4); color: var(--red); border-radius: 8px; padding: 7px 13px; cursor: pointer; font: inherit; font-size: 13px; } .mg-kill:hover { background: rgba(255, 107, 107, 0.14); } .mg-empty { color: var(--text-dim); padding: 30px 0; text-align: center; } /* ── v0.6 Projects panel ─────────────────────────────────────────────────── */ /* Panel wrapper (same host as .launcher; toggled via display) */ .proj-panel { position: absolute; inset: 52px 0 0 0; /* mobile: reserve a row for the stacked .home-seg (desktop overrides to 0) */ overflow-y: auto; padding: 22px 18px 40px; box-sizing: border-box; background: var(--bg); } /* Search box */ .proj-search-wrap { margin-bottom: 16px; } .proj-search { width: 100%; max-width: 320px; padding: 8px 12px; font: inherit; font-size: 14px; color: var(--text); background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 8px; outline: none; box-sizing: border-box; } .proj-search:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); } /* Outer container is now a vertical stack of collapsible namespace sections. */ .proj-grid { display: flex; flex-direction: column; gap: 22px; } /* The actual card grid — one per group (and the flat fallback). Mirrors .mg-grid. */ .proj-grid-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; } /* ── Namespace group section ─────────────────────────────────────────────── */ .proj-group { display: flex; flex-direction: column; gap: 12px; } .proj-group-head { display: flex; align-items: center; gap: 9px; padding: 4px 2px; position: sticky; /* keep the namespace visible while scrolling a long group */ top: 0; z-index: 1; background: var(--bg); user-select: none; } .proj-group-head[role='button'] { cursor: pointer; border-radius: 7px; } .proj-group-head[role='button']:hover { background: var(--surface-1); } .proj-group-head[role='button']:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; } .proj-group-caret { color: var(--text-faint); font-size: 11px; width: 12px; flex: none; text-align: center; } .proj-group-label { color: var(--text); font-weight: 600; font-size: 13px; letter-spacing: 0.01em; } .proj-group-count { color: var(--text-faint); font-size: 12px; font-family: Menlo, Consolas, monospace; } /* "N active" badge on a namespace/other header — never lose running work behind a caret. */ .proj-group-active { color: var(--green); font-size: 11px; margin-left: 2px; } /* "Active now" header — pinned, accent-tinted, non-collapsible. */ .proj-group-head.proj-group-active .proj-group-caret { color: var(--green); font-size: 9px; } .proj-group-head.proj-group-active .proj-group-label { color: var(--accent); } .proj-group.collapsed { gap: 0; } /* Project card */ .proj-card { display: flex; flex-direction: column; gap: 8px; padding: 14px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; transition: border-color 0.12s ease; } .proj-card:hover { border-color: var(--border-strong); } /* Card header row */ .proj-card-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } /* Repo name */ .proj-name { flex: 1 1 auto; color: #fff; font-weight: 600; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Branch chip */ .proj-branch { font-size: 11px; color: var(--accent); background: var(--accent-soft); border-radius: 5px; padding: 2px 7px; white-space: nowrap; flex: none; } /* Dirty indicator (● dot) */ .proj-dirty { font-size: 10px; color: var(--amber); flex: none; } /* W3(a): ahead/behind sync chip (mirrors the .proj-branch chip look). */ .proj-sync { font-size: 11px; color: var(--amber); background: var(--accent-soft); border-radius: 5px; padding: 2px 7px; white-space: nowrap; flex: none; } /* ── w6/G3: the project detail sync band ────────────────────────────────────── Semantic colours here are deliberately NOT the accent: --ok reads "verified, ignore this" and is the one state that may look reassuring, so it must never be reachable from a stale or unknowable comparison (see makeSyncBand). */ .proj-syncband { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0 4px; padding: 9px 12px; background: var(--bg-sunk, rgba(0, 0, 0, 0.22)); border: 1px solid var(--border, rgba(255, 255, 255, 0.08)); border-radius: 8px; } .proj-sync-upstream { font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 11.5px; color: var(--fg-dim, #a8a299); flex: none; } .proj-sync-chip { font-size: 11.5px; font-variant-numeric: tabular-nums; border-radius: 5px; padding: 2px 8px; white-space: nowrap; flex: none; border: 1px solid transparent; } .proj-sync-ahead { color: var(--accent); background: var(--accent-soft); } .proj-sync-behind { color: var(--fg-dim, #a8a299); background: rgba(255, 255, 255, 0.06); } /* The one reassuring state. Reachable only with an upstream AND a fresh fetch. */ .proj-sync-ok { color: #7d9b76; background: rgba(125, 155, 118, 0.13); border-color: rgba(125, 155, 118, 0.3); } /* "This number may be lying" — never applied to ahead, which needs no fetch. */ .proj-sync-stale, .proj-sync-noupstream, .proj-sync-detached { color: #cf6b4f; background: rgba(207, 107, 79, 0.14); border-color: rgba(207, 107, 79, 0.36); } .proj-sync-dirty { color: var(--amber); background: rgba(224, 151, 90, 0.13); } .proj-sync-fetch { margin-left: auto; font: inherit; font-size: 11.5px; cursor: pointer; padding: 4px 12px; border-radius: 6px; border: 1px solid var(--border-strong, rgba(255, 255, 255, 0.14)); background: transparent; color: var(--fg, #ece9e3); } .proj-sync-fetch:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); } .proj-sync-fetch:disabled { opacity: 0.45; cursor: not-allowed; } /* ── w6/G4: unpushed commits + the upstream boundary ───────────────────────── */ .proj-commit-unpushed { position: relative; background: linear-gradient(90deg, var(--accent-soft), transparent 55%); border-radius: 4px; } .proj-commit-unpushed::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; border-radius: 2px; background: var(--accent); } .proj-commit-mark { color: var(--accent); font-size: 11px; flex: none; width: 12px; text-align: center; } /* Where the upstream actually sits in this history — never drawn without one. */ .proj-commit-boundary { display: flex; align-items: center; gap: 10px; margin: 7px 0 5px; } .proj-commit-boundary-label { font-size: 10.5px; color: var(--fg-dim, #a8a299); border: 1px solid var(--border, rgba(255, 255, 255, 0.1)); border-radius: 999px; padding: 2px 10px; white-space: nowrap; flex: none; } .proj-commit-boundary-rule { flex: 1; height: 1px; background: var(--border-strong, rgba(255, 255, 255, 0.14)); } /* w6/G7: running sessions attributed to one worktree row. */ .proj-wt-sessions { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--accent); background: var(--accent-soft); border-radius: 5px; padding: 2px 7px; white-space: nowrap; flex: none; } /* W3(b): cost chip in the per-tab telemetry gauge, warn-styled over budget. */ .tg-cost-warn { color: var(--red); font-weight: 600; } /* W3(d): recent-commit list in the project detail. */ .proj-commitlog { margin: 4px 0 10px; } .proj-commitlog-loading { font-size: 12px; color: var(--text-faint); } .proj-commitlog-list { display: flex; flex-direction: column; gap: 2px; } .proj-commit-row { display: flex; align-items: baseline; gap: 8px; font-size: 12px; min-width: 0; } .proj-commit-hash { font-family: Menlo, Consolas, monospace; color: var(--accent); flex: none; } .proj-commit-time { color: var(--text-faint); flex: none; white-space: nowrap; } .proj-commit-subject { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } .proj-commit-more { font-size: 11px; color: var(--text-faint); margin-top: 4px; } /* W3(c): "while you were away" reconnect banner (compact, dismissible top bar). */ .wya-banner { position: fixed; top: 0; left: 0; right: 0; z-index: 1000; display: flex; align-items: center; gap: 12px; padding: 8px 14px; font-size: 13px; color: var(--text); background: var(--accent-soft); border-bottom: 1px solid var(--accent); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); } .wya-title { font-weight: 600; color: var(--accent); flex: none; } .wya-summary { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .wya-cost { color: var(--text-faint); flex: none; } .wya-dismiss { flex: none; border: none; background: transparent; color: var(--text-faint); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; } .wya-dismiss:hover { color: var(--text); } /* W3: PR + CI status chip (mirrors the .proj-branch chip look). */ .proj-pr-host { display: inline-flex; flex: none; } .proj-pr-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; border-radius: 5px; padding: 2px 7px; white-space: nowrap; max-width: 260px; color: var(--text-faint); background: var(--accent-soft); } .proj-pr-chip .proj-pr-title { overflow: hidden; text-overflow: ellipsis; color: var(--text-faint); } .proj-pr-loading { opacity: 0.6; } /* PR-state modifiers */ .proj-pr-open .proj-pr-label { color: var(--green); } .proj-pr-draft .proj-pr-label { color: var(--text-faint); } .proj-pr-merged .proj-pr-label { color: var(--accent); } .proj-pr-closed .proj-pr-label { color: var(--red); } .proj-pr-none, .proj-pr-unavailable { color: var(--text-faint); background: transparent; } /* Checks-rollup modifiers (colour the whole chip label) */ .proj-pr-checks-ok .proj-pr-label { color: var(--green); } .proj-pr-checks-fail .proj-pr-label { color: var(--red); } .proj-pr-checks-pending .proj-pr-label { color: var(--amber); } /* Mergeable = conflicting */ .proj-pr-conflict { box-shadow: inset 0 0 0 1px var(--red); } /* Meta line (last-active time) */ .proj-meta { font-size: 11px; color: var(--text-faint); font-family: Menlo, Consolas, monospace; } /* Favourite star toggle */ .proj-fav { background: none; border: none; color: var(--text-faint); cursor: pointer; font-size: 15px; padding: 0 2px; line-height: 1; flex: none; transition: color 0.12s ease; } .proj-fav:hover { color: var(--accent); } .proj-fav.on { color: var(--accent); } /* Sessions list (1:N) */ .proj-sessions-list { display: flex; flex-direction: column; gap: 4px; } /* One running-session row */ .proj-session-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 8px; background: var(--surface-3); cursor: pointer; font-size: 13px; color: var(--text); transition: background 0.1s ease; } .proj-session-row:hover { background: rgba(255, 255, 255, 0.08); } /* Status dot on a session row — colours from THEME.md v0.6 note */ .proj-session-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--text-faint); } .proj-dot-working { background: var(--accent); box-shadow: 0 0 5px var(--accent-soft); } .proj-dot-waiting { background: var(--amber); } .proj-dot-idle { background: #8b8a86; } .proj-dot-unknown { background: var(--text-faint); } /* Session title */ .proj-session-title { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Kill (✕) on a session row — close the session straight from the card. */ .proj-session-kill { flex: none; width: 20px; height: 20px; line-height: 1; padding: 0; border: none; border-radius: 5px; background: none; color: var(--text-faint); cursor: pointer; font-size: 11px; transition: background 0.1s ease, color 0.1s ease; } .proj-session-kill:hover { background: var(--red, #e5484d); color: #fff; } /* Client-count badge (👁 N) */ .proj-session-badge { font-size: 11px; color: var(--text-dim); background: var(--surface-2); border-radius: 4px; padding: 1px 5px; flex: none; } /* "+ New" / "+ start claude here" action button */ /* Launcher row — Claude · Codex · VS Code, each a brand-logo icon button. */ .proj-launchers { display: flex; gap: 8px; margin-top: 2px; } .proj-launch { position: relative; /* for the active count badge */ flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 9px 4px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 9px; cursor: pointer; font: inherit; color: var(--text-dim); /* drives the logo colour (currentColor) by default */ transition: background 0.12s ease, border-color 0.12s ease, transform 0.08s ease; } .proj-launch svg { display: block; } .proj-launch-cap { font-size: 11px; font-weight: 600; color: var(--text-dim); } .proj-launch:hover { background: var(--surface-3); border-color: var(--border-strong); transform: translateY(-1px); } .proj-launch:active { transform: translateY(0); } .proj-launch:hover .proj-launch-cap { color: var(--text); } /* Brand colours on the logos (currentColor) */ .proj-launch-claude { color: #d97757; /* Claude coral */ } .proj-launch-codex { color: #e7e8ec; /* OpenAI mark — near-white on dark */ } .proj-launch-vscode { color: #3aa0e3; /* VS Code blue */ } /* Active state — a matching session is running (Claude logo when a Claude * session is live). Coral ring + faint tint draw the eye without shouting. */ .proj-launch-active { background: rgba(217, 119, 87, 0.14); border-color: #d97757; box-shadow: 0 0 0 1px rgba(217, 119, 87, 0.45) inset; } .proj-launch-active .proj-launch-cap { color: #e9b9a6; } .proj-launch-badge { position: absolute; top: 4px; right: 6px; min-width: 15px; height: 15px; padding: 0 3px; box-sizing: border-box; border-radius: 8px; background: #d97757; color: #1a1408; font-size: 9px; font-weight: 700; line-height: 15px; text-align: center; } /* ── Project detail view ─────────────────────────────────────────── */ .proj-name-link { cursor: pointer; } .proj-name-link:hover { text-decoration: underline; text-underline-offset: 2px; } .proj-detail-inner { max-width: 900px; margin: 0 auto; } .proj-back { background: none; border: 1px solid var(--border); color: var(--text-dim); border-radius: 8px; padding: 6px 12px; font: inherit; font-size: 13px; cursor: pointer; margin-bottom: 16px; transition: background 0.12s ease, color 0.12s ease; } .proj-back:hover { background: var(--surface-2); color: var(--text); } .proj-detail-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } .proj-detail-name { margin: 0; font-size: 22px; font-weight: 700; color: #fff; } .proj-detail-path { margin: 4px 0 8px; font-family: Menlo, Consolas, monospace; font-size: 12px; color: var(--text-faint); word-break: break-all; } .proj-section-title { margin: 22px 0 10px; font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint); } /* W5 fan-out form — sibling of the New Worktree form. */ .proj-fanout-form { display: flex; flex-direction: column; gap: 8px; } .proj-fanout-prompt { width: 100%; box-sizing: border-box; resize: vertical; min-height: 44px; font: inherit; } .proj-fanout-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } .proj-fanout-lanes { width: 72px; } .proj-fanout-branch { flex: 1 1 160px; min-width: 120px; } .proj-fanout-error { color: var(--danger, #e5534b); font-size: 12px; } .proj-fanout-submit { align-self: flex-start; } .proj-fanout-submit:disabled { opacity: 0.5; cursor: not-allowed; } /* W5 fan-out status/error banner — fixed, dismissible, textContent only. */ .fanout-banner { position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); max-width: min(680px, 92vw); z-index: 60; padding: 10px 14px; border-radius: 8px; background: var(--surface-3, #2a2c33); color: var(--text, #e7e8ec); border: 1px solid var(--border, #3a3d46); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35); font-size: 13px; cursor: pointer; } /* Section header with an inline action (CLAUDE.md generate/update). */ .proj-section-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 22px 0 10px; } .proj-section-row .proj-section-title { margin: 0; } .proj-claudemd-btn { flex: none; background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--accent); border-radius: 7px; padding: 6px 12px; font: inherit; font-size: 12px; font-weight: 600; cursor: pointer; transition: background 0.12s ease, border-color 0.12s ease; } .proj-claudemd-btn:hover { background: var(--accent-soft); border-color: var(--accent); } .proj-claudemd { margin: 0; max-height: 320px; overflow: auto; padding: 12px 14px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px; font-family: Menlo, Consolas, monospace; font-size: 12px; line-height: 1.5; color: var(--text); white-space: pre-wrap; word-break: break-word; } /* Worktrees */ .proj-wt-list { display: flex; flex-direction: column; gap: 6px; } .proj-wt-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; } .proj-wt-branch { font-weight: 600; color: var(--text); } .proj-wt-tag { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; padding: 2px 7px; border-radius: 999px; background: var(--surface-3); color: var(--text-dim); } .proj-wt-tag-current { background: var(--accent); color: var(--on-accent); } .proj-wt-path { margin-left: auto; font-family: Menlo, Consolas, monospace; font-size: 11px; color: var(--text-faint); word-break: break-all; } /* Detailed session rows */ .proj-detail-sessions { display: flex; flex-direction: column; gap: 8px; } .proj-dsession { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; } .proj-dsession-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; } .proj-dsession-title { font-weight: 600; color: var(--text); } .proj-dsession-meta { font-size: 12px; color: var(--text-dim); } .proj-dsession-open { background: var(--accent); color: var(--on-accent); border: none; border-radius: 7px; padding: 6px 14px; font: inherit; font-weight: 600; cursor: pointer; } .proj-dsession-open:hover { background: var(--accent-2); } .proj-dsession-kill { background: none; border: 1px solid var(--border); color: var(--text-dim); border-radius: 7px; width: 30px; height: 30px; cursor: pointer; font-size: 14px; } .proj-dsession-kill:hover { background: var(--red, #e5484d); border-color: var(--red, #e5484d); color: #fff; } /* Empty state */ .proj-empty { color: var(--text-dim); padding: 30px 0; text-align: center; } /* ── Home segmented control (P6 builds the DOM; styles defined here per spec) */ /* Horizontal pill container, centered above the home grid */ /* Segmented control: a single rounded "track" holding two pill buttons, with * the active one filled (iOS-style). Centred with fit-content + margin auto. */ .home-seg { width: fit-content; margin: 10px auto 12px; display: flex; gap: 3px; padding: 3px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; } /* Inactive segment */ .home-seg-btn { background: transparent; border: none; color: var(--text-dim); cursor: pointer; font: inherit; font-size: 13px; font-weight: 500; padding: 6px 22px; border-radius: 999px; transition: background 0.12s ease, color 0.12s ease; } .home-seg-btn:not(.active):hover { color: var(--text); background: var(--surface-3); } /* Active segment — Amber accent; text uses --on-accent for contrast */ .home-seg-btn.active { background: var(--accent); color: var(--on-accent); font-weight: 600; } .home-seg-btn.active:hover { background: var(--accent-2); } /* On the home chooser (Sessions/Projects), there is no active terminal, so the * bottom key-bar is just noise — hide it. Toggled by TabApp.updateHomeView(). */ body.home-open #keybar { display: none; } /* Home chooser hides the key-bar, so reclaim its reserved space at the bottom * (keeping the home-indicator clearance so launcher content stays reachable). */ body.home-open #term { bottom: var(--safe-b); } /* Desktop: float the Sessions/Projects toggle top-right, on the SAME row as the * panel's filter/header — instead of a dedicated row that left a big empty band. * The panels fill from the top; the launcher header reserves room for the pill. * (Mobile keeps the stacked, centred toggle — see .home-seg above — to avoid * overlapping the full-width filter box on narrow screens.) */ @media (min-width: 769px) { .home-seg { position: absolute; top: 16px; right: 20px; margin: 0; z-index: 6; } .launcher, .proj-panel { inset: 0; } .launcher-head { padding-right: 240px; /* clear the absolutely-positioned .home-seg */ } } /* v0.7: timeline + push toggle reuse the minimal .toolbtn look. */ .toolbtn.active { color: var(--accent); } .toolbtn.push-bell-disabled { opacity: 0.45; cursor: default; } .toolbtn.push-bell-disabled:hover { background: none; color: var(--text-dim); } /* v0.7 fix: timeline + push toggle render as minimal line-icon buttons that match the .toolbtn toolbar style (transparent, monochrome, accent on hover/active). !important defeats the earlier boxed default for these classes. */ .tab-timeline, .push-toggle-btn, .push-toggle-disabled { background: none !important; border: none !important; box-shadow: none !important; color: var(--text-dim); cursor: pointer; display: inline-flex; align-items: center; gap: 4px; padding: 7px 9px; border-radius: 8px; font: inherit; font-size: 12px; line-height: 1; transition: background 0.12s ease, color 0.12s ease; } .tab-timeline svg, .push-toggle-btn svg, .push-bell svg { width: 18px; height: 18px; display: block; } .tab-timeline:hover, .push-toggle-btn:hover { color: var(--accent); background: var(--surface-2) !important; } .tab-timeline.active, .push-toggle-btn.push-toggle-on { color: var(--accent); } .push-toggle-disabled { color: var(--text-faint); opacity: 0.6; cursor: default; } .push-hint { font-size: 11px; color: var(--text-faint); } /* v0.7: styled hover tooltip on the timeline + push buttons (like .toolbtn). Left-anchored — these sit on the left side of the tab bar. */ .tab-timeline, .push-toggle-btn { position: relative; } .tab-timeline[data-tip]::after, .push-toggle-btn[data-tip]::after { content: attr(data-tip); position: absolute; top: calc(100% + 6px); left: 0; white-space: nowrap; background: var(--surface-3); color: var(--text); border: 1px solid var(--border-strong); padding: 4px 8px; border-radius: 6px; font-size: 12px; font-weight: 500; opacity: 0; pointer-events: none; transition: opacity 0.12s ease; z-index: 60; } .tab-timeline[data-tip]:hover::after, .push-toggle-btn[data-tip]:hover::after { opacity: 1; } /* ── Saved layout presets dropdown (v3) ──────────────────────────────── */ .grid-presets { position: relative; display: inline-flex; margin-left: 2px; } .grid-presets-btn { border: 1px solid var(--border); background: var(--surface-2); color: var(--text-dim); width: 30px; height: 30px; border-radius: 8px; cursor: pointer; font-size: 13px; } .grid-presets-btn:hover { color: var(--text); background: var(--surface-3); } .grid-presets-menu { position: absolute; top: calc(100% + 6px); right: 0; min-width: 220px; background: var(--surface-1); border: 1px solid var(--border-strong); border-radius: 10px; box-shadow: var(--shadow); padding: 6px; z-index: 40; } .grid-presets-menu[hidden] { display: none; } .gp-list { display: flex; flex-direction: column; gap: 2px; max-height: 240px; overflow-y: auto; } .gp-empty { color: var(--text-faint); font-size: 12px; padding: 8px; text-align: center; } .gp-row { display: flex; align-items: center; gap: 4px; } .gp-apply { flex: 1; display: flex; align-items: center; justify-content: space-between; gap: 8px; border: 0; background: transparent; color: var(--text); padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 12.5px; text-align: left; } .gp-apply:hover { background: var(--surface-2); } .gp-apply-layout { color: var(--text-faint); font-size: 11px; } .gp-del { border: 0; background: transparent; color: var(--text-faint); width: 22px; height: 22px; border-radius: 5px; cursor: pointer; font-size: 15px; line-height: 1; } .gp-del:hover { color: var(--red); background: var(--surface-2); } .gp-save { display: flex; gap: 4px; margin-top: 6px; border-top: 1px solid var(--border); padding-top: 6px; } .gp-name { flex: 1; min-width: 0; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--text); padding: 5px 8px; font-size: 12px; font-family: var(--ui-font); } .gp-name:focus { outline: none; border-color: var(--accent); } .gp-save-btn { border: 0; background: var(--accent); color: var(--on-accent); border-radius: 6px; padding: 5px 10px; cursor: pointer; font-size: 12px; font-weight: 600; } .gp-save-btn:hover { filter: brightness(1.05); } /* ── W4 git write: per-file Stage/Unstage toggle + commit/push bar ─────────── */ .df-file-header { display: flex; align-items: center; gap: 8px; } .df-file-stage { margin-left: auto; flex: 0 0 auto; padding: 3px 10px; font-size: 12px; border: 1px solid var(--border-strong); border-radius: 6px; background: var(--surface-2); color: var(--text); cursor: pointer; } .df-file-stage:hover { background: var(--surface-3); border-color: var(--accent); } .df-commitbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; padding: 10px; border-top: 1px solid var(--border); background: var(--surface-1); } .df-commit-msg { flex: 1 1 220px; min-width: 0; resize: vertical; padding: 8px; font: inherit; color: var(--text); background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 6px; } .df-commit-msg:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } .df-commit-btn, .df-push-btn { flex: 0 0 auto; padding: 8px 16px; font: inherit; font-weight: 600; border-radius: 6px; border: 1px solid var(--accent); background: var(--accent); color: #1a1712; cursor: pointer; } .df-push-btn { background: var(--surface-2); color: var(--text); border-color: var(--border-strong); } .df-commit-btn:disabled, .df-push-btn:disabled { opacity: 0.5; cursor: not-allowed; } .df-op-status { flex: 1 1 100%; font-size: 13px; word-break: break-word; } .df-op-error { color: var(--red); } .df-op-notice { color: var(--text-dim); } .df-op-busy { opacity: 0.7; }