/* * V2 design tokens + base styles. All v2 styles are scoped under .v2-root * so the existing app's global CSS does not bleed in (and vice versa). */ /* The ONE deliberate exception to the .v2-root scope: the page canvas. App.tsx unconditionally stamps `modern-ui` (V1's dark gradient) on ; .v2-root paints only its own box, so the V1 dark showed through on load flash, overscroll rubber-banding, and every gap. V2App stamps `v2-canvas` while mounted; the compound selector out-ranks body.modern-ui (0-2-1 > 0-1-1) so bundle order cannot decide this. Literal color: body sits outside .v2-root, so tokens don't reach it — keep in lockstep with --v2-page-bg below. */ body.v2-canvas, body.modern-ui.v2-canvas { background: #f8f8fb; } .v2-root { /* Palette */ --v2-bg: #ffffff; --v2-page-bg: #eef0f4; --v2-bg-subtle: #f9fafb; --v2-surface: #ffffff; --v2-surface-tint: #f2f4f7; --v2-surface-hover: #f2f4f7; --v2-border: #d0d5dd; --v2-border-soft: #e4e7ec; --v2-border-strong: #98a2b3; --v2-text-primary: #101828; --v2-message-text: #1f2937; /* TASK-701: inactive rail glyphs, join-radio outlines (3:1 on white and #f2f4f7) and the neutral selected pod row. Dark values sit in both dark sets below. */ /* D223 ruling (Cofounder, 11-01): the artboard's --ph (#98a2b3) measures 2.34:1 on #f2f4f7, under the 3:1 above, so this is the nearest grey that passes: 3.07:1 on #f2f4f7, 3.38:1 on white. */ --v2-rail-icon: #848c9b; --v2-control-outline: #667085; /* D223 (TASK-735): the artboard's .pod.on in both themes, a neutral tint row whose mark alone turns cobalt. */ --v2-row-active: #f2f4f7; --v2-row-active-text: #101828; --v2-row-active-mute: #667085; --v2-row-active-mark: #1d3fd1; --v2-text-secondary: #475467; --v2-text-tertiary: #667085; --v2-text-muted: #667085; --v2-text-placeholder: #98a2b3; /* The tint step (TASK-122) in the Signal identity: shell ground #eef0f4 behind rail, pods and inspector; the content pane is an inset white card with a 1px #d0d5dd ring and a 6px radius — hard edges, no shadow. Mirrors --c-shell-bg / --c-content-radius in design-system/tokens.css. */ --v2-shell-bg: #eef0f4; --v2-content-radius: 6px; /* Character-avatar grounds (TASK-679, Lit Signal). The fill behind each face is generated in utils/avatars.ts CHARACTER_GROUNDS, which must match these values; avatarGrounds.test.ts pins the two together. Agents are cool, people warm, so the family still tells the species apart. Mirrors --c-avatar-* in design-system/tokens.css. */ --v2-avatar-agent-1: #dbe5f1; --v2-avatar-agent-2: #e1e6ee; --v2-avatar-agent-3: #d6e7e4; --v2-avatar-human-1: #f1e7df; --v2-avatar-human-2: #f2e8d8; --v2-avatar-human-3: #efe1dc; --v2-avatar-human-4: #f4e3d7; --v2-avatar-frame: rgba(16, 24, 40, 0.06); /* Dark ring (TASK-679 dark note): the tile stays light on dark, so the ring flips to a light hairline. No dark theme on main yet; TASK-680 points --v2-avatar-frame at this value under its dark scope. */ --v2-avatar-frame-dark: rgba(255, 255, 255, 0.10); /* Ink primary — filled buttons are ink; cobalt (#1d3fd1) is a MARK inside the app: links, the live dot, the agent name, the one card that needs you. On marketing surfaces cobalt is used as blocks. Mirrors --c-ink. */ --v2-ink: #101828; --v2-ink-hover: #1d2939; --v2-on-ink: #ffffff; --v2-on-accent: #ffffff; --v2-accent-fill: #1d3fd1; /* BEND-1 (spec 2026-08-30): the featured-tier name needs a step between 16 and 20. Mirrors --c-fs-feature in design-system/tokens.css; the two move together. */ --v2-fs-feature: 17px; --v2-accent: #1d3fd1; --v2-accent-strong: #1633a8; --v2-accent-soft: #e9edfb; --v2-accent-text: #1d3fd1; --v2-accent-deep: #0f2378; --v2-focus-ring: 0 0 0 3px rgba(29, 63, 209, 0.18); /* Platform brand + tint tokens (connectors) — mirror of --c-platform-* in design-system/tokens.css; the two move together. */ --v2-platform-telegram: #2aabee; --v2-platform-telegram-soft: #e4f3fb; --v2-platform-slack: #611f69; --v2-platform-slack-soft: #f3e9f4; --v2-platform-discord: #5865f2; --v2-platform-discord-soft: #eaecfe; --v2-platform-whatsapp: #1fa855; --v2-platform-whatsapp-soft: #e5f6ec; --v2-platform-x: #111827; --v2-platform-x-soft: #eef0f3; --v2-platform-instagram: #d62976; --v2-platform-instagram-soft: #fbe9f1; --v2-platform-messenger: #0084ff; --v2-platform-messenger-soft: #e5f2ff; --v2-platform-groupme: #00aff0; --v2-platform-groupme-soft: #e3f5fd; --v2-success: #10b981; /* Text-on-soft success — one canonical value (#1368: a second ad-hoc success-text hex is how a third one happens). Mirrors --c-success-text in design-system/tokens.css. */ --v2-success-text: #0f7a53; --v2-success-soft: #e3f6ec; --v2-success-ring: rgba(16, 185, 129, 0.40); --v2-success-ring-strong: rgba(16, 185, 129, 0.50); --v2-warning: #f4a23a; --v2-warning-soft: #fdefdc; --v2-info: #0891b2; --v2-info-soft: #dff4f8; --v2-danger: #ef4444; --v2-danger-text: #b91c1c; --v2-danger-soft: rgba(239, 68, 68, 0.10); /* TASK-687/698: board status and priority colour, the D215 B-lite choice (Sam, 10-31). Blocked and P0 are red; in progress stays cobalt; P1, P2, pending and done stay grey, with no green. Each state keeps its shape. Dark values are in both dark blocks below. */ --v2-prio-p0-bg: #b42318; --v2-prio-p0-fg: #ffffff; --v2-prio-ink: var(--v2-text-secondary); --v2-prio-p2-fg: #667085; --v2-prio-edge: var(--v2-border); --v2-status-live: var(--v2-accent); --v2-status-idle: var(--v2-border-strong); --v2-status-pending: #667085; --v2-status-blocked: #d92d20; --v2-status-blocked-edge: #d92d20; /* Agent role colors */ --v2-pink: #f472b6; --v2-violet: #a78bfa; --v2-amber: #fbbf24; --v2-emerald: #34d399; --v2-sky: #60a5fa; --v2-rose: #fb7185; /* Typography — the Signal identity (direction C on the Shell Parity canvas, 2026-09-03). Three faces, each with one job: Bricolage Grotesque for display (headings, wordmarks — weight 700/800), IBM Plex Sans for every line of body and control text, IBM Plex Mono for meta (timestamps, ids, status). All self-hosted via @fontsource, imported in V2App.tsx above this sheet; the system stacks are fallbacks only while woff2 loads. Mirrors --c-font-* in design-system/tokens.css. */ --v2-font: "IBM Plex Sans", "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; --v2-font-display: "Bricolage Grotesque Variable", "Bricolage Grotesque", "Helvetica Neue", Arial, sans-serif; --v2-fs-body: 14px; --v2-lh-body: 20px; --v2-fs-meta: 12px; --v2-lh-meta: 16px; --v2-fs-label: 11px; --v2-lh-label: 14px; --v2-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; /* Geometry */ --v2-radius-sm: 4px; --v2-radius: 4px; --v2-radius-lg: 6px; --v2-radius-pill: 999px; /* D223 Signal primitives (TASK-730), from the d215 artboard :root. Additive: the old --v2-radius-*/--v2-shadow-* values above stay until PR2 moves consumers onto the scale. Pinned by __tests__/signalTokens.test.ts. */ --v2-ink-2: #1d2433; --v2-fill-a: #333c4e; --v2-fill-b: #161d2c; --v2-fill-edge: #0b101b; --v2-on-fill: #ffffff; --v2-accent-fill-a: #2e50e2; --v2-accent-fill-b: #1b3bc6; --v2-key-a: #ffffff; --v2-key-b: #f4f5f7; --v2-key-edge: rgba(15, 23, 42, 0.14); --v2-key-inset: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 1px 2px rgba(16, 24, 40, 0.06); --v2-shadow-pane: 0 0 0 1px rgba(16, 24, 40, 0.07), 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -20px rgba(16, 24, 40, 0.18); --v2-shadow-pop: 0 0 0 1px rgba(16, 24, 40, 0.08), 0 2px 4px rgba(16, 24, 40, 0.04), 0 18px 36px -14px rgba(16, 24, 40, 0.28); --v2-av-ring: rgba(16, 24, 40, 0.07); --v2-scrim: rgba(16, 24, 40, 0.18); --v2-font-display: "Bricolage Grotesque", "Helvetica Neue", Arial, sans-serif; --v2-r-6: 6px; --v2-r-8: 8px; --v2-r-9: 9px; --v2-r-10: 10px; --v2-r-12: 12px; --v2-r-14: 14px; /* Elevation */ --v2-shadow-sm: none; --v2-shadow: none; --v2-shadow-lg: none; --v2-shadow-pending: none; /* the one chrome-card shadow: a PENDING decision or approval only */ /* Layout */ --v2-rail-w: 56px; --v2-pods-w: 260px; --v2-inspector-w: 272px; /* Keep production's scoped V2 layer in step with design-system/tokens.css. The typing cadence belongs to the minimal mark; pulse/spin retain their separate state-affordance semantics. */ --motion-stagger: 0.18s; --motion-breath: 1.2s; --motion-pulse: 1.6s; --motion-spin: 0.8s; --motion-ease-breath: ease-in-out; --motion-ease-state: ease-out; --motion-ease-linear: linear; font-family: var(--v2-font); color: var(--v2-text-primary); background: var(--v2-page-bg); height: 100vh; width: 100vw; overflow: hidden; display: flex; flex-direction: column; font-size: var(--v2-fs-body); line-height: var(--v2-lh-body); min-width: 0; } /* D216 dark set. Values are the artboard's dark :root (index.html, the @media + :root[data-theme="dark"] pair), mapped onto v2 token names. Scoped to .v2-root under the html attribute set by utils/theme.ts: explicit dark, or auto when the OS asks for dark. The light set is the block above. Not from the artboard, pending ux-lead: --v2-focus-ring, the success and danger text lifts, and the soft fills. Avatar and persona tints stay literal. */ :root[data-v2-theme="dark"] .v2-root { /* D223 Signal primitives (TASK-730); dark values from the d215 artboard. */ --v2-ink-2: #d3d8e1; --v2-fill-a: #f4f5f8; --v2-fill-b: #dce0e8; --v2-fill-edge: #c4cad5; --v2-on-fill: #0b0e13; --v2-accent-fill-a: #3d5ef2; --v2-accent-fill-b: #2948d8; --v2-key-a: #1e2531; --v2-key-b: #191f29; --v2-key-edge: rgba(255, 255, 255, 0.10); --v2-key-inset: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 1px 2px rgba(0, 0, 0, 0.3); --v2-shadow-pane: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 12px 28px -20px rgba(0, 0, 0, 0.6); --v2-shadow-pop: 0 0 0 1px rgba(255, 255, 255, 0.10), 0 18px 36px -14px rgba(0, 0, 0, 0.75); --v2-av-ring: rgba(255, 255, 255, 0.10); --v2-scrim: rgba(0, 0, 0, 0.45); --v2-bg: #141922; --v2-page-bg: #0b0e13; --v2-bg-subtle: #181e28; --v2-surface: #141922; --v2-surface-tint: #1e2531; --v2-surface-hover: #1e2531; --v2-border: #364051; --v2-border-soft: #262d3a; --v2-border-strong: #5f6979; --v2-prio-p0-bg: #f97066; --v2-prio-p0-fg: #0b0e13; --v2-prio-p2-fg: #8b94a5; --v2-status-pending: var(--v2-border-strong); --v2-status-blocked: #f97066; --v2-status-blocked-edge: #f97066; --v2-text-primary: #e8ebf1; --v2-message-text: #e8ebf1; --v2-rail-icon: #5f6979; --v2-control-outline: #737e92; --v2-row-active: #1e2531; --v2-row-active-text: #e8ebf1; --v2-row-active-mute: #8b94a5; --v2-row-active-mark: #6680ff; --v2-text-secondary: #aeb6c4; --v2-text-tertiary: #8b94a5; --v2-text-muted: #8b94a5; --v2-text-placeholder: #5f6979; --v2-shell-bg: #0b0e13; --v2-ink: #f4f5f8; --v2-ink-hover: #dce0e8; --v2-on-ink: #0b0e13; --v2-accent: #6680ff; --v2-accent-strong: #3d5ef2; --v2-accent-soft: #1b2546; --v2-accent-text: #8aa2ff; --v2-accent-deep: #2948d8; --v2-focus-ring: 0 0 0 2px var(--v2-bg), 0 0 0 4px #8aa2ff; --v2-success-text: #3ccf95; --v2-success-soft: rgba(16, 185, 129, 0.16); --v2-danger-text: #ff8a8a; --v2-danger-soft: rgba(239, 68, 68, 0.16); --v2-on-accent: #ffffff; --v2-accent-fill: #3d5ef2; --v2-warning-soft: rgba(244, 162, 58, 0.16); --v2-info-soft: rgba(8, 145, 178, 0.16); --v2-platform-x: #e8ebf1; --v2-platform-x-soft: rgba(17, 24, 39, 0.16); --v2-platform-telegram-soft: rgba(42, 171, 238, 0.16); --v2-platform-slack-soft: rgba(97, 31, 105, 0.16); --v2-platform-discord-soft: rgba(88, 101, 242, 0.16); --v2-platform-whatsapp-soft: rgba(31, 168, 85, 0.16); --v2-platform-instagram-soft: rgba(214, 41, 118, 0.16); --v2-platform-messenger-soft: rgba(0, 132, 255, 0.16); --v2-platform-groupme-soft: rgba(0, 175, 240, 0.16); color-scheme: dark; } @media (prefers-color-scheme: dark) { :root:not([data-v2-theme="light"]) .v2-root { /* D223 Signal primitives (TASK-730); dark values from the d215 artboard. */ --v2-ink-2: #d3d8e1; --v2-fill-a: #f4f5f8; --v2-fill-b: #dce0e8; --v2-fill-edge: #c4cad5; --v2-on-fill: #0b0e13; --v2-accent-fill-a: #3d5ef2; --v2-accent-fill-b: #2948d8; --v2-key-a: #1e2531; --v2-key-b: #191f29; --v2-key-edge: rgba(255, 255, 255, 0.10); --v2-key-inset: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 1px 2px rgba(0, 0, 0, 0.3); --v2-shadow-pane: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 12px 28px -20px rgba(0, 0, 0, 0.6); --v2-shadow-pop: 0 0 0 1px rgba(255, 255, 255, 0.10), 0 18px 36px -14px rgba(0, 0, 0, 0.75); --v2-av-ring: rgba(255, 255, 255, 0.10); --v2-scrim: rgba(0, 0, 0, 0.45); --v2-bg: #141922; --v2-page-bg: #0b0e13; --v2-bg-subtle: #181e28; --v2-surface: #141922; --v2-surface-tint: #1e2531; --v2-surface-hover: #1e2531; --v2-border: #364051; --v2-border-soft: #262d3a; --v2-border-strong: #5f6979; --v2-prio-p0-bg: #f97066; --v2-prio-p0-fg: #0b0e13; --v2-prio-p2-fg: #8b94a5; --v2-status-pending: var(--v2-border-strong); --v2-status-blocked: #f97066; --v2-status-blocked-edge: #f97066; --v2-text-primary: #e8ebf1; --v2-message-text: #e8ebf1; --v2-rail-icon: #5f6979; --v2-control-outline: #737e92; --v2-row-active: #1e2531; --v2-row-active-text: #e8ebf1; --v2-row-active-mute: #8b94a5; --v2-row-active-mark: #6680ff; --v2-text-secondary: #aeb6c4; --v2-text-tertiary: #8b94a5; --v2-text-muted: #8b94a5; --v2-text-placeholder: #5f6979; --v2-shell-bg: #0b0e13; --v2-ink: #f4f5f8; --v2-ink-hover: #dce0e8; --v2-on-ink: #0b0e13; --v2-accent: #6680ff; --v2-accent-strong: #3d5ef2; --v2-accent-soft: #1b2546; --v2-accent-text: #8aa2ff; --v2-accent-deep: #2948d8; --v2-focus-ring: 0 0 0 2px var(--v2-bg), 0 0 0 4px #8aa2ff; --v2-success-text: #3ccf95; --v2-success-soft: rgba(16, 185, 129, 0.16); --v2-danger-text: #ff8a8a; --v2-danger-soft: rgba(239, 68, 68, 0.16); --v2-on-accent: #ffffff; --v2-accent-fill: #3d5ef2; --v2-warning-soft: rgba(244, 162, 58, 0.16); --v2-info-soft: rgba(8, 145, 178, 0.16); --v2-platform-x: #e8ebf1; --v2-platform-x-soft: rgba(17, 24, 39, 0.16); --v2-platform-telegram-soft: rgba(42, 171, 238, 0.16); --v2-platform-slack-soft: rgba(97, 31, 105, 0.16); --v2-platform-discord-soft: rgba(88, 101, 242, 0.16); --v2-platform-whatsapp-soft: rgba(31, 168, 85, 0.16); --v2-platform-instagram-soft: rgba(214, 41, 118, 0.16); --v2-platform-messenger-soft: rgba(0, 132, 255, 0.16); --v2-platform-groupme-soft: rgba(0, 175, 240, 0.16); color-scheme: dark; } } .v2-root *, .v2-root *::before, .v2-root *::after { box-sizing: border-box; } /* Thin overlay-style scrollbars on every scroll container inside v2. Without this, Linux + Windows Chrome show a chunky default scrollbar with a gray track that clashes with the otherwise-flat surfaces. macOS Chrome paints overlay scrollbars by default and is unaffected. */ .v2-root *::-webkit-scrollbar { width: 8px; height: 8px; } .v2-root *::-webkit-scrollbar-track { background: transparent; } .v2-root *::-webkit-scrollbar-thumb { background: var(--v2-border-strong); border-radius: 4px; border: 2px solid transparent; background-clip: padding-box; } .v2-root *::-webkit-scrollbar-thumb:hover { background: var(--v2-text-tertiary); background-clip: padding-box; border: 2px solid transparent; } .v2-root *::-webkit-scrollbar-corner { background: transparent; } /* Firefox + modern Chrome standard property. */ .v2-root * { scrollbar-width: thin; scrollbar-color: var(--v2-border-strong) transparent; } .v2-root :where(button:not(.MuiButtonBase-root)) { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; padding: 0; } .v2-root input, .v2-root textarea { font-family: inherit; color: inherit; } .v2-root a { color: inherit; text-decoration: none; } /* ---------- Language switch ---------- */ /* Language dropdown. The trigger deliberately reads like a plain nav option (no pill chrome) so it sits naturally among nav links; the menu is a small anchored card. */ .v2-lang-switch { position: relative; display: inline-flex; } .v2-lang-switch__trigger { display: inline-flex; align-items: center; gap: 4px; padding: 4px 6px; border-radius: var(--v2-radius-sm, 8px); color: var(--v2-text-secondary); font-size: 13px; font-weight: 500; line-height: 1; transition: color 80ms ease; } .v2-lang-switch__trigger:hover { color: var(--v2-text-primary); } .v2-lang-switch__menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 40; min-width: 132px; margin: 0; padding: 6px; list-style: none; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: 10px; box-shadow: var(--v2-shadow-md, 0 8px 24px rgba(16, 24, 40, 0.12)); } .v2-lang-switch__item { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 14px; min-height: 34px; padding: 8px 12px; border-radius: 7px; color: var(--v2-text-secondary); font-size: 13px; text-align: left; transition: background 80ms ease, color 80ms ease; } .v2-lang-switch__item:hover { background: var(--v2-bg-subtle); color: var(--v2-text-primary); } .v2-lang-switch__item--active { color: var(--v2-accent-text); font-weight: 600; } .v2-lang-switch__check { font-size: 11px; } /* ---------- Shared filter grammar ---------- */ .v2-filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 10px; margin-bottom: 16px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); } .v2-filter-bar--flat { padding: 0; border: none; background: transparent; } .v2-filter-bar__search { flex: 1 1 280px; min-width: 220px; } .v2-filter-bar__control { flex: 0 1 180px; min-width: 160px; } .v2-filter-bar__action { flex: 0 0 auto; } .v2-filter-bar__summary { margin-left: auto; color: var(--v2-text-tertiary); font-size: 12px; font-weight: 500; white-space: nowrap; } .v2-filter-segment { display: flex; flex-wrap: wrap; gap: 6px; } .v2-filter-segment__item { min-height: 30px; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-pill); background: var(--v2-surface); color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; transition: background 80ms ease, border-color 80ms ease, color 80ms ease; } .v2-filter-segment__item:hover { border-color: var(--v2-border-strong); background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-filter-segment__item--active { border-color: var(--v2-accent); background: var(--v2-accent); color: var(--v2-surface); font-weight: 700; } .v2-filter-count { margin-left: 5px; color: inherit; font-size: 11px; font-weight: 700; opacity: 0.68; } .v2-active-filter-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: -4px 0 16px; color: var(--v2-text-tertiary); font-size: 12px; } .v2-root button:focus-visible, .v2-root input:focus-visible, .v2-root textarea:focus-visible, .v2-root a:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } /* ---------- Layout shell ---------- */ /* Authenticated v2 routes reserve a compact shell row for the email verification reminder. The inner shell/panes must use the remaining space, not 100vh, or the composer and feature-page footers would clip. */ .v2-authenticated-shell { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); height: 100vh; min-height: 0; overflow: hidden; } .v2-authenticated-shell__content { /* Row 2 always, not by auto-placement. Row 1 is the `auto` row the banner sits in, so a verified user (no banner) has the content as the FIRST grid child and auto-placement put it in that row instead: the inset card then sized to its own content and any page shorter than the viewport ended 178-195px above the bottom gutter instead of 14 (TASK-157, ux-lead at 1200). Row 1 collapses to 0 with nothing in it, which is the same layout the banner variant already produced. */ grid-row: 2; min-width: 0; min-height: 0; overflow: hidden; } .v2-authenticated-shell__content > .v2-shell, .v2-authenticated-shell__content .v2-pane { height: 100%; } .v2-verification-banner { box-sizing: border-box; display: grid; grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "content resend dismiss"; align-items: center; gap: 8px; min-width: 0; min-height: 40px; padding: 4px 16px; border-bottom: 1px solid var(--v2-border-soft); background: var(--v2-warning-soft); color: var(--v2-text-primary); font-size: 14px; line-height: 20px; } .v2-verification-banner__content { grid-area: content; min-width: 0; } .v2-verification-banner__text { display: block; overflow-wrap: anywhere; } /* Resend feedback stays in the visible status reminder so a sighted person receives the same confirmation as assistive technology. */ .v2-verification-banner__notice { display: block; margin-top: 2px; color: var(--v2-text-secondary); font-size: 13px; line-height: 18px; } .v2-root button.v2-verification-banner__resend, .v2-root button.v2-verification-banner__dismiss { flex: none; min-height: 44px; border: 0; background: transparent; color: var(--v2-accent-text); font: inherit; font-weight: 650; cursor: pointer; } .v2-root button.v2-verification-banner__resend { grid-area: resend; padding: 4px 4px; } .v2-root button.v2-verification-banner__dismiss { grid-area: dismiss; display: grid; width: 44px; height: 44px; padding: 0; place-items: center; color: var(--v2-text-secondary); } .v2-root button.v2-verification-banner__resend:disabled { cursor: progress; opacity: 0.7; } .v2-shell { display: grid; grid-template-columns: var(--v2-rail-w) var(--v2-pods-w) 1fr var(--v2-inspector-w); grid-template-rows: 1fr; height: 100vh; width: 100%; background: var(--v2-shell-bg); } .v2-shell--no-inspector { grid-template-columns: var(--v2-rail-w) var(--v2-pods-w) 1fr; } .v2-shell--feature { grid-template-columns: var(--v2-rail-w) var(--v2-pods-w) minmax(0, 1fr); } .v2-shell--feature-wide { grid-template-columns: var(--v2-rail-w) minmax(0, 1fr); } .v2-pane { height: 100vh; overflow: hidden; display: flex; flex-direction: column; border-right: 1px solid transparent; /* the content card's ring replaces the pane hairlines */ background: var(--v2-shell-bg); } .v2-pane--rail { background: var(--v2-shell-bg); /* The 56px rail lets the language menu, attention badge and nav hover labels escape the pane instead of clipping them at its edge. */ overflow: visible; } /* The content pane is the inset card: 8px gutter top/right/bottom, 1px ring, 14px radius (TASK-122). Height subtracts the gutters; the banner variant beats `.v2-authenticated-shell__content .v2-pane { height: 100% }` on specificity. */ .v2-pane--main { margin: 8px 8px 8px 0; height: calc(100vh - 16px); background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: var(--v2-content-radius); overflow: hidden; } .v2-authenticated-shell .v2-pane--main { height: calc(100% - 16px); } /* Inspector open: the card meets the inspector gutter. --feature-wide has no inspector column, so it keeps its right gutter. */ .v2-shell:not(.v2-shell--no-inspector):not(.v2-shell--feature):not(.v2-shell--feature-wide) .v2-pane--main { margin-right: 0; } .v2-pane--inspector { border-right: none; border-left: 1px solid var(--v2-border-soft); background: var(--v2-shell-bg); } .v2-inspector-backdrop { display: none; } /* Mobile pods-drawer affordances — hidden on desktop, where the pods sidebar is a permanent grid column. The <=760px media query (bottom of file) turns these on and converts .v2-pods-aside into a slide-over overlay. Declared here so resizing a phone-open drawer up to desktop can't leak the overlay or backdrop into the normal multi-column layout. */ .v2-mobile-backdrop { display: none; } .v2-pods__mobile-close { display: none; } /* ---------- Nav rail ---------- */ .v2-rail { height: 100%; padding: 6px 10px; display: flex; flex-direction: column; gap: 8px; justify-content: space-between; } /* Bottom of the rail: a help/preferences cluster (language · guide · feedback) sits above a divider, then the account cluster (avatar · sign out). */ .v2-rail__foot { display: flex; flex-direction: column; align-items: center; gap: 10px; } .v2-rail__utility { display: flex; flex-direction: column; align-items: center; gap: 8px; } .v2-rail__foot-sep { width: 24px; height: 1px; background: var(--v2-border); } /* The language switch left the rail for Settings › Look (D215, TASK-691). */ .v2-rail__brand { display: flex; align-items: center; justify-content: center; gap: 0; font-weight: 700; font-size: 17px; padding: 0; margin-bottom: 8px; color: var(--v2-text-primary); letter-spacing: -0.02em; height: 36px; } .v2-rail__brand > span:not(.v2-rail__brand-icon) { display: none; } /* D223 (TASK-735): the artboard's .logo, a 36px cobalt key. */ .v2-rail__brand-icon { width: 36px; height: 36px; border-radius: var(--v2-r-10, 10px); background: var(--v2-accent); background: linear-gradient(180deg, var(--v2-accent-fill-a, var(--v2-accent)), var(--v2-accent-fill-b, var(--v2-accent))); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 6px 12px -6px rgba(29, 63, 209, 0.5); color: #fff; display: grid; place-items: center; font-weight: 800; font-size: 14px; } .v2-rail__nav { display: flex; flex: 1; flex-direction: column; gap: 8px; min-height: 0; overflow: visible; padding-right: 0; } /* Below the rail's fixed chrome (245px) plus six nav items (268px), scroll the nav vertically while keeping its horizontal overflow hidden. */ @media (max-height: 460px) { .v2-rail__nav { overflow-y: auto; overflow-x: hidden; } } .v2-root button.v2-rail__item { position: relative; display: flex; align-items: center; justify-content: center; gap: 0; /* D223 (TASK-735): the artboard's .nav, a bare 38px glyph at rest. The glyph colour stays the TASK-701 token, so dark keeps its lift. */ width: 38px; min-height: 38px; height: 38px; align-self: center; padding: 0; border-radius: var(--v2-r-10, 10px); font-size: 14px; font-weight: 600; color: var(--v2-rail-icon); background: transparent; text-align: left; transition: background 80ms ease; } .v2-rail__item:hover::after, .v2-rail__item:focus-visible::after { content: attr(data-label); position: absolute; left: calc(100% + 8px); top: 50%; transform: translateY(-50%); z-index: 10; padding: 5px 8px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); font-size: 12px; font-weight: 600; white-space: nowrap; } .v2-root button.v2-rail__item:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-rail__item--active { background: var(--v2-ink); background: linear-gradient(180deg, var(--v2-fill-a, var(--v2-ink)), var(--v2-fill-b, var(--v2-ink))); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 4px 10px -3px rgba(16, 24, 40, 0.3); color: var(--v2-on-fill, var(--v2-on-ink)); font-weight: 600; } .v2-rail__item-icon { width: 20px; height: 20px; display: grid; place-items: center; flex-shrink: 0; } .v2-rail__item-label { display: none; } .v2-rail__divider { width: 24px; height: 1px; margin: 6px auto; background: var(--v2-border); } .v2-rail__user { min-height: 48px; padding: 0; display: flex; flex-direction: column; align-items: center; gap: 8px; border-top: none; } .v2-rail__user > div { display: none; } .v2-rail__feedback, .v2-rail__signout, .v2-rail__account { width: 24px; height: 24px; display: grid; place-items: center; border-radius: var(--v2-radius-sm); color: var(--v2-text-tertiary); background: transparent; border: none; cursor: pointer; transition: background 80ms ease, color 80ms ease; } .v2-rail__feedback:hover, .v2-rail__feedback[aria-expanded="true"], .v2-rail__signout:hover, .v2-rail__account:hover, .v2-rail__account[aria-expanded="true"] { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-rail__feedback svg, .v2-rail__signout svg { width: 18px; height: 18px; } .v2-rail__account { width: 36px; height: 36px; padding: 0; } /* The artboard's .av--36: a 36px square, 9px corners, a hairline ring. */ .v2-rail__account .v2-avatar { width: 36px; height: 36px; border: 0; border-radius: var(--v2-r-9, 9px); box-shadow: 0 0 0 1px var(--v2-av-ring, var(--v2-border-soft)); pointer-events: none; } .v2-root .v2-account-menu__popover.MuiPaper-root { min-width: 190px; margin-left: 8px; overflow: hidden; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); color: var(--v2-text-primary); box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12); } .v2-account-menu__list { display: flex; flex-direction: column; gap: 2px; padding: 6px; } .v2-root button.v2-account-menu__item { display: flex; align-items: center; gap: 10px; min-height: 38px; padding: 8px 10px; border: 0; border-radius: var(--v2-radius-sm); background: transparent; color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; text-align: left; cursor: pointer; } .v2-root button.v2-account-menu__item:hover, .v2-root button.v2-account-menu__item:focus-visible { background: var(--v2-surface-hover); color: var(--v2-text-primary); outline: none; } .v2-root button.v2-account-menu__item:focus-visible { box-shadow: var(--v2-focus-ring); } .v2-account-menu__item svg { width: 18px; height: 18px; color: var(--v2-text-tertiary); } .v2-root .v2-feedback-menu__popover.MuiPaper-root { min-width: 210px; margin-left: 8px; overflow: hidden; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); color: var(--v2-text-primary); box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12); } .v2-feedback-menu__list { display: flex; flex-direction: column; gap: 2px; padding: 6px; } .v2-feedback-menu__item { display: flex; align-items: center; gap: 10px; min-height: 38px; padding: 8px 10px; border-radius: var(--v2-radius-sm); color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; transition: background 80ms ease, color 80ms ease; } .v2-feedback-menu__item:hover, .v2-feedback-menu__item:focus-visible { background: var(--v2-surface-hover); color: var(--v2-text-primary); outline: none; } .v2-feedback-menu__item:focus-visible { box-shadow: var(--v2-focus-ring); } .v2-feedback-menu__item svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--v2-text-tertiary); } .v2-rail__user-name { font-weight: 700; font-size: 13px; } .v2-rail__user-status { font-size: 12px; color: var(--v2-success); display: flex; align-items: center; gap: 4px; } .v2-online-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--v2-success); display: inline-block; } /* ---------- Pods sidebar ---------- */ .v2-pods { display: flex; flex-direction: column; height: 100%; padding: 24px 16px; } .v2-pods__header { padding: 0; display: flex; flex-direction: column; gap: 0; } .v2-pods__title { height: 32px; font-size: 16px; font-weight: 700; letter-spacing: -0.02em; margin-bottom: 14px; } .v2-root button.v2-pods__new-btn { display: flex; align-items: center; justify-content: center; height: 40px; gap: 8px; background: var(--v2-accent-fill); color: var(--v2-on-accent); font-weight: 600; font-size: 14px; padding: 0 14px; border-radius: var(--v2-radius-sm); transition: background 80ms ease; margin-bottom: 16px; } .v2-root button.v2-pods__new-btn:hover { background: var(--v2-accent-strong); } .v2-pods__create { display: flex; flex-direction: column; gap: 7px; padding: 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); margin-bottom: 14px; } /* Who can join is separate from public visibility. The default remains open; * invite-only is needed before a private pod can hold an outsider-writable * connector grant. These are radios rather than the old option buttons whose * styling lost to the global button reset (#870). */ .v2-pods__join-policy, .v2-pod-join-settings { display: flex; min-width: 0; flex-direction: column; gap: 6px; margin: 3px 0; padding: 0; border: 0; color: var(--v2-text-secondary); font: 400 12px/16px var(--v2-font); } .v2-pods__join-policy legend, .v2-pod-join-settings legend { margin-bottom: 6px; color: var(--v2-text-primary); font-weight: 600; } .v2-pods__join-policy label, .v2-pod-join-settings label { display: flex; align-items: center; gap: 8px; min-height: 40px; cursor: pointer; } /* Native radios ignore border tokens, so draw the outline from one. Checked, the border thickens into the accent dot, so no cobalt background is added. */ .v2-pods__join-policy input, .v2-pod-join-settings input { appearance: none; width: 14px; height: 14px; margin: 0; flex-shrink: 0; border: 1.5px solid var(--v2-control-outline); border-radius: 50%; background: var(--v2-surface); cursor: pointer; } .v2-pods__join-policy input:checked, .v2-pod-join-settings input:checked { border: 4px solid var(--v2-accent); } .v2-pods__join-policy-hint { margin: 0; color: var(--v2-text-secondary); font: 400 var(--v2-fs-meta)/16px var(--v2-font); } .v2-pod-join-settings__error { margin: 8px 0 0; color: var(--v2-danger); font: 400 12px/16px var(--v2-font); } .v2-pods__create-input { width: 100%; padding: 8px 9px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); font-size: 12px; outline: none; } .v2-pods__create-input:focus { border-color: var(--v2-accent); } .v2-pods__create-error { font-size: 11px; color: var(--v2-danger); } .v2-pods__create-actions { display: flex; justify-content: flex-end; gap: 8px; } .v2-root button.v2-pods__create-cancel, .v2-root button.v2-pods__create-submit { padding: 6px 9px; border-radius: var(--v2-radius-sm); font-size: 12px; font-weight: 700; } .v2-root button.v2-pods__create-cancel { color: var(--v2-text-tertiary); } .v2-root button.v2-pods__create-submit { background: var(--v2-ink); color: var(--v2-on-ink); } .v2-root button.v2-pods__create-submit:disabled { background: var(--v2-border-strong); cursor: not-allowed; } @media (max-width: 760px) { .v2-root button.v2-pods__create-cancel, .v2-root button.v2-pods__create-submit { min-height: 40px; } } .v2-pods__filters { /* Fourth mechanism for this row (2026-08-23): every chip the SAME size, at least as roomy as the widest label. Content-sized chips read ragged (EN measured 33/49/44/84px), and four equal cells cannot share one 239px rail — "Community" alone needs 84px. Equal therefore means a 2×2 grid, the exact mechanism .v2-pods__community-tabs below already uses, so the two stacked sections align by construction. This retires the 2026-08-13 one-row intent deliberately. */ display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; padding: 0; margin-bottom: 18px; flex-shrink: 0; overflow: visible; } /* Keep the explicit button prefix on the chip state rules so their visual treatment remains intentional above the low-specificity default reset. This used to be required to beat the reset; the reset is now scoped through `:where()` so bare component rules can own their declarations. */ .v2-root button.v2-pods__filter { height: 32px; min-width: 0; padding: 0 10px; font-size: 12px; font-weight: 500; color: #4b5563; border-radius: var(--v2-radius-sm); text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: background 80ms ease, color 80ms ease; } .v2-pods__filter:hover { color: var(--v2-text-primary); background: var(--v2-surface-hover); } /* Must sit AFTER the base chip rule: both this and the shared .v2-root button.v2-filter-segment__item--active rule weigh 0-2-1, so source order decides — with the base chip rule later in the file, the selected chip shipped grey-on-blue (measured live 2026-08-23). */ .v2-root button.v2-pods__filter--active { background: var(--v2-accent); color: var(--v2-surface); font-weight: 700; } .v2-pods__community-tabs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; margin: -10px 0 14px; flex-shrink: 0; overflow: hidden; } .v2-pods__community-tab { min-width: 0; padding-inline: 8px; white-space: nowrap; } .v2-pods__list { flex: 1; overflow-y: auto; padding: 0; } .v2-pods__group-label { padding: 0; margin: 18px 0 8px; font-size: 12px; font-weight: 600; color: var(--v2-text-muted); } .v2-pods__item { display: grid; grid-template-columns: 34px minmax(0, 1fr); align-items: start; gap: 10px; height: 64px; padding: 10px; overflow: hidden; border-radius: var(--v2-radius); cursor: pointer; width: 100%; text-align: left; transition: background 80ms ease; border: 1px solid transparent; } .v2-pods__item:hover { background: var(--v2-surface-hover); } /* The explicit root/button selector keeps the selected row treatment above the low-specificity default reset. Source order then resolves the local active-row variants. */ .v2-root button.v2-pods__item--active { background: var(--v2-accent-soft); border-color: transparent; position: relative; } .v2-root button.v2-pods__item--active::before { content: ''; position: absolute; left: -8px; top: 12px; bottom: 12px; width: 3px; border-radius: 0 2px 2px 0; background: var(--v2-accent); } .v2-pods__item-icon { width: 34px; height: 34px; border-radius: var(--v2-radius); display: grid; place-items: center; flex-shrink: 0; font-size: 11px; letter-spacing: 0.04em; color: var(--v2-text-secondary); font-weight: 700; background: var(--v2-surface-hover); text-transform: uppercase; border: 1px solid var(--v2-border-soft); } .v2-pods__item-icon--team { background: var(--v2-surface-hover); border-color: var(--v2-border-soft); color: var(--v2-text-secondary); } .v2-pods__item-icon--private { background: #f3f4f6; color: var(--v2-text-secondary); } .v2-pods__item--active .v2-pods__item-icon--team, .v2-pods__item--active .v2-pods__item-icon--private { background: var(--v2-accent); border-color: transparent; color: #fff; } .v2-pods__item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; } .v2-pods__item-title-row { display: flex; align-items: flex-start; gap: 6px; min-width: 0; min-height: 20px; } /* Craft baseline rule 1: the pod name is the row's primary identifier and never loses to its own timestamp — wrap to two lines instead of ellipsizing (same idiom as the team-card name fix, #1104). The clamp keeps pathological names from unbounding the row; the timestamp lives on the snippet row so it never shares a line with the name. */ .v2-pods__item-title { flex: 1; min-width: 0; font-size: 14px; line-height: 20px; font-weight: 600; color: var(--v2-text-primary); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; } .v2-pods__item-snippet-row { display: flex; align-items: baseline; gap: 6px; min-width: 0; } .v2-pods__item-snippet-row .v2-pods__item-snippet { flex: 1; min-width: 0; } .v2-pods__status { height: 18px; padding: 0 6px; border-radius: 999px; display: inline-flex; align-items: center; flex-shrink: 0; font-size: 10px; font-weight: 700; color: var(--v2-text-tertiary); background: var(--v2-surface); } .v2-pods__status--agents { color: var(--v2-text-secondary); background: var(--v2-surface-hover); } .v2-pods__status--empty { color: var(--v2-text-tertiary); background: var(--v2-surface); } .v2-pods__status--direct { color: var(--v2-text-secondary); background: #f3f4f6; } .v2-pods__item--active .v2-pods__item-title { color: var(--v2-accent-text); } /* Unread state: title becomes bolder + body picks up an accent dot. Active pods are never marked unread, so the active treatment above wins. */ .v2-pods__item--unread .v2-pods__item-title { font-weight: 700; color: var(--v2-text-primary); } .v2-pods__item--unread .v2-pods__item-snippet { color: var(--v2-text-secondary); } .v2-pods__item-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--v2-accent); flex-shrink: 0; /* The title-row went align-items: flex-start for the 2-line name wrap (#1110), which parked this dot flush at the row's top-right corner — inside the row's border-radius + overflow:hidden clip, so the rounding visibly shaved the dot (2026-08-22). Center it on the first 20px text line and inset it clear of the 10px corner curve. */ margin-top: 6px; margin-right: 4px; } .v2-pods__item-snippet--typing { color: var(--v2-accent-text); font-style: italic; } .v2-pods__item-meta { font-size: 12px; color: var(--v2-text-tertiary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-pods__item-snippet { font-size: 12px; line-height: 16px; color: var(--v2-text-tertiary); display: block; height: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Title-row sibling — sits to the right of the pod name. Slack/iMessage pattern: the timestamp lives on the same line as the title so the second line is reserved entirely for the message preview. */ .v2-pods__item-time { flex-shrink: 0; /* Relative-time formatting follows the viewer's browser locale. Do not cap it to an English measurement: title ellipsis is safer than clipping a clock, and visibility:hidden still reserves this row's slot on hover. */ font-size: 11px; color: var(--v2-text-tertiary); font-variant-numeric: tabular-nums; align-self: baseline; text-align: right; white-space: nowrap; } .v2-pods__empty { padding: 32px 16px; text-align: center; color: var(--v2-text-tertiary); font-size: 13px; } .v2-pods__join-notice { margin-bottom: 8px; padding: 9px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface-hover); color: var(--v2-text-secondary); font-size: 12px; line-height: 1.4; } .v2-pods__discover-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; align-items: center; gap: 10px; padding: 10px; margin-bottom: 6px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); background: var(--v2-surface); } .v2-pods__discover-body { min-width: 0; display: flex; flex-direction: column; gap: 3px; } .v2-pods__discover-title { overflow: hidden; color: var(--v2-text-primary); font-size: 13px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; } .v2-pods__discover-description { overflow: hidden; color: var(--v2-text-tertiary); display: -webkit-box; font-size: 12px; line-height: 1.35; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } .v2-pods__discover-meta { color: var(--v2-text-muted); font-size: 11px; } .v2-root button.v2-pods__discover-join { min-width: 44px; min-height: 30px; padding-inline: 9px; border-radius: var(--v2-radius-sm); background: var(--v2-accent-soft); color: var(--v2-accent-text); font-size: 12px; font-weight: 700; } .v2-root button.v2-pods__discover-join:hover { background: var(--v2-accent); color: var(--v2-surface); } .v2-root button.v2-pods__discover-join:disabled { cursor: wait; opacity: 0.65; } .v2-pods__community { flex-shrink: 0; margin-top: 12px; padding: 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); } .v2-pods__community-title { color: var(--v2-text-primary); font-size: 13px; font-weight: 700; } .v2-pods__community-copy { margin-top: 3px; color: var(--v2-text-tertiary); font-size: 12px; line-height: 1.4; } .v2-root button.v2-pods__community-button { width: 100%; min-height: 34px; margin-top: 10px; border-radius: var(--v2-radius-sm); background: var(--v2-accent-soft); color: var(--v2-accent-text); font-size: 12px; font-weight: 700; transition: background 80ms ease, color 80ms ease; } .v2-root button.v2-pods__community-button:hover { background: var(--v2-accent); color: var(--v2-surface); } /* ---------- Pod chat (main) ---------- */ .v2-chat { display: flex; flex-direction: column; height: 100%; min-width: 0; } .v2-chat__header { min-height: 78px; padding: 14px 24px; border-bottom: 1px solid var(--v2-border-soft); background: var(--v2-surface); display: flex; flex-direction: column; justify-content: center; gap: 7px; } .v2-chat__header-row { display: flex; align-items: center; gap: 10px; } .v2-chat__title { font-size: 20px; font-weight: 700; display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; letter-spacing: -0.025em; } .v2-chat__title-mark { width: 28px; height: 28px; border-radius: var(--v2-radius-sm); display: grid; place-items: center; background: var(--v2-surface-hover); color: var(--v2-text-secondary); font-size: 11px; font-weight: 700; letter-spacing: 0.04em; flex-shrink: 0; } .v2-chat__title-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-chat__avatars { display: flex; align-items: center; } .v2-chat__avatars > * + * { margin-left: -8px; } /* When the avatar group is the inspector entry, treat it like a button: subtle hover shadow that hints "this is clickable" without an explicit chevron. Active state means the inspector is open. */ .v2-chat__avatars--button { background: transparent; border: 1px solid transparent; border-radius: var(--v2-radius-pill); padding: 3px 6px; cursor: pointer; transition: background 80ms ease, border-color 80ms ease; } .v2-chat__avatars--button:hover { background: var(--v2-surface-hover); } .v2-chat__avatars--active { background: var(--v2-surface-hover); border-color: var(--v2-surface-hover); } .v2-chat__avatars--active:hover { background: var(--v2-surface-hover); } .v2-chat__avatars-more { background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-size: 11px; font-weight: 600; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; border: 2px solid var(--v2-surface); } .v2-chat__btn { display: flex; align-items: center; height: 34px; gap: 6px; padding: 0 14px; font-size: 13px; font-weight: 600; color: #374151; border: 1px solid #e5e7eb; border-radius: var(--v2-radius-sm); background: var(--v2-surface); transition: background 80ms ease, color 80ms ease; } .v2-chat__btn:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-chat__icon-btn { width: 34px; height: 34px; display: grid; place-items: center; color: #6b7280; border: 1px solid #e5e7eb; border-radius: var(--v2-radius-sm); background: var(--v2-surface); transition: background 80ms ease, color 80ms ease; } .v2-chat__icon-btn:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-chat__mode-toggle { display: inline-flex; align-items: center; gap: 2px; height: 34px; padding: 3px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-bg-subtle); } /* Keep the explicit root/button selector on the mode control so the active state owns its background and color rather than relying on reset order. */ .v2-root button.v2-chat__mode-option { height: 26px; display: inline-flex; align-items: center; gap: 5px; padding: 0 9px; border-radius: var(--v2-radius-sm); background: transparent; color: var(--v2-text-secondary); font-size: 12px; font-weight: 600; } .v2-root button.v2-chat__mode-option:hover { color: var(--v2-text-primary); background: var(--v2-surface); } .v2-root button.v2-chat__mode-option--active { background: var(--v2-ink); color: var(--v2-on-ink); } .v2-root button.v2-chat__mode-option--active:hover { background: var(--v2-ink-hover); color: var(--v2-on-ink); } .v2-chat__goal { font-size: 13px; color: #4b5563; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 720px; } .v2-chat__state-strip { min-height: 42px; margin: 12px 24px 0; padding: 8px 12px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-lg); background: var(--v2-bg-subtle); display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; gap: 12px; } .v2-chat__state-strip--execute { border-color: var(--v2-border-soft); background: var(--v2-bg-subtle); } .v2-chat__state-primary { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 700; } .v2-chat__state-copy { min-width: 0; color: var(--v2-text-secondary); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-chat__state-meta { color: var(--v2-text-tertiary); font-size: 12px; font-weight: 600; } /* "Load older messages" control — the pod chat equivalent of the showcase pager. Same pill treatment so the two reading surfaces match. */ .v2-chat__older { display: flex; justify-content: center; padding: 4px 0 12px; } .v2-chat__older-btn { padding: 7px 16px; font: inherit; font-size: 13px; font-weight: 600; color: var(--v2-text-secondary); background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: 999px; cursor: pointer; } .v2-chat__older-btn:hover:not(:disabled) { color: var(--v2-text-primary); border-color: var(--v2-text-tertiary); } .v2-chat__older-btn:disabled { opacity: 0.6; cursor: default; } /* Catch-up strip — the constant agents-TL;DR pinned above the transcript (2026-09-01). One thin row; the expanded body is bounded so a long summary scrolls inside the strip, never the pane. */ .v2-catchup { border-bottom: 1px solid var(--v2-border); background: var(--v2-surface); padding: 6px 20px; font-size: 13px; } .v2-catchup__row { display: flex; align-items: center; gap: 10px; min-width: 0; } .v2-root button.v2-catchup__toggle { background: transparent; border: none; padding: 0; font-size: 13px; font-weight: 650; color: var(--v2-text-secondary); cursor: pointer; white-space: nowrap; } .v2-root button.v2-catchup__toggle:hover:not(:disabled) { color: var(--v2-text-primary); } .v2-root button.v2-catchup__toggle:disabled { cursor: default; } .v2-catchup__chevron { display: inline-block; margin-right: 4px; transition: transform 0.08s ease; } .v2-catchup__chevron--open { transform: rotate(90deg); } .v2-catchup__time { font-weight: 400; color: var(--v2-text-tertiary); } .v2-catchup__snippet { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--v2-text-tertiary); } .v2-root button.v2-catchup__refresh { background: transparent; border: none; padding: 0; font-size: 12px; color: var(--v2-accent); cursor: pointer; white-space: nowrap; } .v2-root button.v2-catchup__refresh:hover:not(:disabled) { text-decoration: underline; } .v2-root button.v2-catchup__refresh:disabled { color: var(--v2-text-tertiary); cursor: default; } .v2-root button.v2-catchup__dismiss { background: transparent; border: none; padding: 0 2px; font-size: 14px; line-height: 1; color: var(--v2-text-tertiary); cursor: pointer; } .v2-root button.v2-catchup__dismiss:hover { color: var(--v2-text); } .v2-catchup__body { margin-top: 6px; max-height: 220px; overflow-y: auto; white-space: pre-wrap; color: var(--v2-text-secondary); line-height: 1.5; } .v2-chat__messages { flex: 1; overflow-y: auto; /* The transcript never scrolls sideways — wide content (code, tables) manages its own overflow-x inside its message. Without this, any mis-sized row makes the whole pane horizontally swipeable (the thread-block did exactly that; mobile report 2026-08-24). */ overflow-x: hidden; padding: 0 24px 12px; display: flex; flex-direction: column; gap: 0; } /* Only the managed history operation disables native anchoring. Leaving the default on at rest keeps late image loads above a reader's viewport stable; V2Thread measures and compensates the history row itself. */ .v2-chat__messages[data-history-anchor="active"] { overflow-anchor: none; } /* The transcript is the chat viewport's positioning context. History recovery belongs to this viewport rather than the top of the scrollable message list, otherwise a failure after a deep landing is stranded above the reader's current scroll position. */ .v2-thread__transcript { position: relative; display: flex; flex: 1; min-height: 0; } .v2-thread__transcript > .v2-chat__messages { min-height: 0; } /* Conversation width — FIFTH revision of craft rule 2, ruled 2026-08-23: FULL-WIDTH, the Slack/Discord model. The measure cap died with its last corner: v1 centered messages alone (island), v2/v4 left-anchored the cap (dead space on the right once the inspector closes), v3 centered the whole column (rejected outright). With a line cap, leftover space must pool somewhere — so the cap goes. Rows and text span the pane and wrap at its edge; lines run long on wide windows, the familiar chat tradeoff. What survives every revision: one shared left edge for every conversation row, and margin-inline stays an EXPLICIT 0 so a stray auto cannot re-center a subset. */ .v2-chat__messages > * { width: 100%; margin-inline: 0; } .v2-chat__composer > * { margin-inline: 0; } /* Sender-only teaching cue shown once per pod/session when a message reaches a pod with agents but addresses none of them. Aligns with message text, stays quiet/secondary, and disappears naturally with transcript scroll. Box geometry is NOT here: it belongs to the side-row slot rule below, which this row shares with the no-agent row. */ .v2-chat__delivery-hint { color: var(--v2-text-tertiary); font-size: 12px; line-height: 1.4; } .v2-chat__delivery-hint strong { color: var(--v2-ink); font-weight: 600; } /* The transcript's two side-rows — the sender-only delivery cue above and the no-agent row below — occupy ONE slot, and that slot IS the message text column of the transcript they sit in. Both are siblings of `.v2-msg` inside `.v2-chat__messages`, so the indent is the avatar track plus the gap of the rule that governs those rows HERE, which is the thread override `.v2-thread .v2-msg { grid-template-columns: 28px minmax(0, 1fr); gap: 8px }` — 28 + 8 = 36, NOT the base `.v2-msg` grid (38 + 12 = 50), which that override replaces (0,3,0 beats 0,1,0). The first cut of this rule derived from the base grid and was 14px out; ux-lead's #1860 gate measured it at 390, 720 and 1440 — 50px put both rows 14px right of `.v2-msg__content`, 36px put them on it (injection on their fixture, right edge and scrollWidth unchanged). Both placements of these rows share their message's container (transcript level, or inside a `.v2-thread-block` for a thread root), so the same relative indent holds in both. The width subtracts the same indent: `.v2-chat__messages > *` sets width: 100%, so an indent without its complement overruns the pane by exactly the indent. That was the #1846 defect — at 390 the full-width act ran 64→426 and the body line was cut (ux-lead's shot, 2026-09-23) — and the same class one indent over on `.v2-thread-block` (2026-08-24): indent + width must sum to 100%. One rule for both rows, so they cannot drift apart again: this is the only place either row's box is declared, and v2-layout-invariants.test.ts derives the expected indent from `.v2-thread .v2-msg`'s own grid, so moving that column fails the suite instead of silently misaligning these rows. */ .v2-chat__delivery-hint, .v2-chat__no-agents, .v2-chat__starts { width: calc(100% - 36px); margin: -4px 0 8px 36px; } /* The delivery hint above requires an agent to name (`agentsInPod > 0`), which leaves out the pod where nothing can answer at all — a team pod with no agent installed. This row sits in the same slot under the sent message, says why the send went quiet, and carries the one step that changes it. Ink and tint only: nothing here succeeded, and no accent or toast should say otherwise. */ .v2-chat__no-agents { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; /* Box geometry lives in the shared side-row slot rule above, next to the delivery cue it shares the slot with. */ } .v2-chat__no-agents-kicker { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 11px; font-weight: 500; line-height: 16px; text-transform: lowercase; } .v2-chat__no-agents-body { color: var(--v2-text-secondary); font-size: 12px; line-height: 1.4; } .v2-root button.v2-chat__no-agents-action { min-height: 32px; padding: 0 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); color: var(--v2-text-primary); font-size: 12px; font-weight: 600; transition: background 80ms ease, border-color 80ms ease; } .v2-root button.v2-chat__no-agents-action:hover { background: var(--v2-surface-hover); } /* Scout's starts (first session, direction B, ruled 2026-10-15): the welcome's offers, one bordered button per start, in one column at one width so they read as a set. A click sends the start as the person's own message. Box geometry lives in the shared side-row slot rule above. */ .v2-chat__starts { display: grid; grid-template-columns: minmax(0, max-content); gap: 6px; } .v2-root button.v2-chat__start { min-height: 32px; padding: 6px 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); color: var(--v2-text-primary); font-size: 13px; font-weight: 500; line-height: 1.35; text-align: left; white-space: normal; transition: background 80ms ease, border-color 80ms ease; } .v2-root button.v2-chat__start:hover:not(:disabled) { background: var(--v2-surface-hover); border-color: var(--v2-border-strong); } .v2-root button.v2-chat__start:disabled { opacity: 0.6; cursor: default; } /* TASK-647 item 4: the run-hosted start is the screen's one filled action. Keyed on the action in the component, not on its position. */ .v2-root button.v2-chat__start.v2-chat__start--primary { background: var(--v2-ink); border-color: var(--v2-ink); color: var(--v2-on-ink); font-weight: 600; } .v2-root button.v2-chat__start.v2-chat__start--primary:hover:not(:disabled) { background: var(--v2-ink-hover); border-color: var(--v2-ink-hover); } /* A line that belongs to the start above it: the hosted start's beta limits, or why it could not start. Same slot and size as the delivery hint. */ .v2-chat__start-note { margin: -2px 0 2px; color: var(--v2-text-tertiary); font-size: 12px; line-height: 1.4; } .v2-chat__start-note--error { color: var(--v2-danger); } @media (max-width: 760px) { /* The row's single act is a touch target on a phone: full width of the row, 44 tall. This must override the MINIMUM, not a height — a `height` here would lose to the base rule's own min-height and render 32 (TASK-140). */ .v2-root button.v2-chat__no-agents-action { width: 100%; min-height: 44px; } /* Scout's starts are touch targets too: 44 tall on a phone, as drawn. */ .v2-root button.v2-chat__start { min-height: 44px; } } /* First-run is a shell-level dialog. The overlay separates the one-time setup path from pod content, while the dialog itself owns overflow on short mobile viewports so every step and the dismissal control stay reachable. */ .v2-first-run__overlay { position: fixed; inset: 0; z-index: 120; display: grid; place-items: center; overflow-y: auto; padding: 24px; background: rgba(15, 23, 42, 0.42); } .v2-first-run { width: min(720px, 100%); max-height: calc(100dvh - 48px); overflow-y: auto; padding: 28px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); color: var(--v2-text-primary); box-shadow: var(--v2-shadow-md, 0 8px 24px rgba(15, 23, 42, 0.12)); outline: none; } .v2-first-run__eyebrow { margin-bottom: 8px; color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; } .v2-first-run__heading-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; } .v2-first-run__title { margin: 0; font-size: clamp(22px, 3vw, 30px); line-height: 1.15; letter-spacing: -0.025em; } .v2-first-run__lede { max-width: 560px; margin: 10px 0 0; color: var(--v2-text-secondary); font-size: 14px; line-height: 1.55; } .v2-root button.v2-first-run__skip { flex-shrink: 0; padding: 4px 0; color: var(--v2-text-tertiary); font-size: 12px; font-weight: 600; } .v2-root button.v2-first-run__skip:hover { color: var(--v2-text-primary); } .v2-first-run__steps { display: grid; gap: 14px; margin: 24px 0 0; padding: 0; list-style: none; } .v2-first-run__step { display: grid; grid-template-columns: 30px minmax(0, 1fr); gap: 12px; align-items: start; padding: 14px; border-radius: var(--v2-radius); background: var(--v2-bg-subtle); } .v2-first-run__step-mark { display: grid; place-items: center; width: 28px; height: 28px; border: 1px solid var(--v2-border); border-radius: 50%; background: var(--v2-surface); color: var(--v2-text-secondary); font-size: 12px; font-weight: 700; } .v2-first-run__step-mark--done { border-color: var(--v2-border); background: var(--v2-surface); color: var(--v2-accent); } .v2-first-run__step-body { display: flex; min-width: 0; flex-direction: column; align-items: flex-start; gap: 5px; color: var(--v2-text-secondary); font-size: 13px; line-height: 1.45; } .v2-first-run__step-body strong { color: var(--v2-text-primary); font-size: 14px; } .v2-root a.v2-first-run__setup, .v2-root button.v2-first-run__hello { display: inline-flex; align-items: center; gap: 6px; min-height: 34px; margin-top: 6px; padding: 8px 12px; border-radius: var(--v2-radius-sm); background: var(--v2-ink); color: var(--v2-on-ink); font-size: 12px; font-weight: 700; text-decoration: none; } .v2-root a.v2-first-run__setup { /* Bordered, not ink: the first-run card keeps one ink action (TASK-647 item 4). */ background: var(--v2-surface); border: 1px solid var(--v2-border); color: var(--v2-text-primary); } .v2-root a.v2-first-run__setup:hover { background: var(--v2-surface-hover); border-color: var(--v2-border-strong); } .v2-root button.v2-first-run__hello:hover:not(:disabled) { background: var(--v2-ink-hover); color: var(--v2-on-ink); } .v2-root button.v2-first-run__hello:disabled { cursor: wait; opacity: 0.65; } .v2-first-run__connected { color: var(--v2-success); font-weight: 700; } .v2-first-run__error { color: var(--v2-danger); font-size: 12px; } .v2-chat__error { padding: 9px 12px; border-radius: 8px; background: rgba(239, 68, 68, 0.08); color: var(--v2-danger); font-size: 12px; border: 1px solid rgba(239, 68, 68, 0.16); } .v2-chat__system { display: flex; align-items: center; gap: 10px; padding: 10px 14px; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: var(--v2-radius); font-size: 13px; color: var(--v2-text-secondary); } .v2-chat__system-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--v2-success); flex-shrink: 0; } /* Sender-only delivery feedback sits under the post as a quiet system line. */ .v2-msg__sender-notice { color: var(--v2-text-tertiary); font: 12px/16px var(--v2-font); margin-top: 6px; } .v2-root .v2-msg__sender-notice a { color: var(--v2-accent); text-decoration: underline; } /* Agent typing indicator — sits between message list and composer. Collapses to nothing when typingAgents is empty. Subtle so it doesn't compete with the messages above; the animated dots carry the "alive" cue. */ .v2-chat__typing { display: flex; align-items: center; gap: 8px; padding: 6px 24px; border-top: 1px solid var(--v2-border-soft); color: var(--v2-text-tertiary); font-size: 12px; flex-shrink: 0; min-height: 28px; } .v2-chat__typing-avatars { display: inline-flex; } .v2-chat__typing-avatars > * + * { margin-left: -6px; } .v2-chat__typing-label { flex-shrink: 0; } .v2-chat__typing-dots { display: inline-flex; align-items: center; gap: 3px; margin-left: 2px; } .v2-chat__typing-dots > span { width: 4px; height: 4px; border-radius: 50%; background: var(--v2-text-tertiary); animation: v2-typing-dot var(--motion-breath) infinite var(--motion-ease-breath); } .v2-chat__typing-dots > span:nth-child(2) { animation-delay: var(--motion-stagger); } .v2-chat__typing-dots > span:nth-child(3) { animation-delay: calc(var(--motion-stagger) + var(--motion-stagger)); } @keyframes v2-typing-dot { 0%, 60%, 100% { transform: translateY(0); opacity: 0.35; } 30% { transform: translateY(-3px); opacity: 1; } } .v2-chat__composer { padding: 12px 24px 14px; border-top: 1px solid var(--v2-border-soft); background: var(--v2-surface); flex-shrink: 0; } /* A 1:1 agent room must not make a successful POST look like an active agent. The liveness row is deliberately adjacent to, but outside, the composer: it remains visible while someone writes and never becomes part of the scrollable transcript. */ .v2-chat__agent-room-status { margin: 8px 24px 0; padding: 8px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-size: 12px; line-height: 1.4; } .v2-chat__agent-room-command { display: block; margin-top: 4px; font-family: var(--v2-font-mono, ui-monospace, monospace); overflow-wrap: anywhere; user-select: all; } .v2-team-card__fix { display: block; margin-top: 4px; font-family: var(--v2-font-mono, ui-monospace, monospace); font-size: 12px; color: var(--v2-text-secondary); overflow-wrap: anywhere; user-select: all; } .v2-chat__agent-room-status--wait { border-color: var(--v2-border); background: var(--v2-surface-hover); color: var(--v2-text-secondary); font-family: var(--v2-font-mono); font-weight: 500; } .v2-chat__agent-room-status-dot { width: 6px; height: 6px; flex: 0 0 auto; border-radius: 50%; background: var(--v2-success); } .v2-chat__agent-room-status--timeout { border-color: var(--v2-border-strong); background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-weight: 500; } .v2-chat__starter-prompts { display: flex; flex-wrap: wrap; gap: 8px; /* Part of the conversation column: siblings of the messages list share its full pane width and left edge (rule 2 v5, full-width) — a second edge here recreates the v1 island. max-width keeps the mobile-shrink property the 390px pane needs. */ width: 100%; max-width: 100%; margin-inline: 0; padding: 10px 24px 0; background: var(--v2-surface); flex-shrink: 0; } .v2-chat__new-pod { align-self: center; width: min(760px, 100%); margin: auto; padding: 24px; border: 1px solid var(--v2-border-strong); border-radius: var(--v2-radius-lg); background: var(--v2-bg-subtle); } .v2-chat__new-pod-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 16px; } .v2-chat__new-pod-title { color: var(--v2-text-primary); font-size: 20px; font-weight: 700; letter-spacing: -0.02em; } .v2-chat__new-pod-text { max-width: 520px; margin-top: 4px; color: var(--v2-text-secondary); font-size: 13px; line-height: 1.45; } .v2-root button.v2-chat__new-pod-dismiss { display: grid; flex: 0 0 auto; width: 28px; height: 28px; place-items: center; border-radius: var(--v2-radius-sm); color: var(--v2-text-tertiary); } .v2-root button.v2-chat__new-pod-dismiss:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-chat__new-pod-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; } .v2-root button.v2-chat__new-pod-action, .v2-chat__new-pod-action { display: flex; min-width: 0; min-height: 88px; flex-direction: column; align-items: flex-start; gap: 5px; padding: 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); color: var(--v2-text-primary); text-align: left; } .v2-root button.v2-chat__new-pod-action { transition: background 80ms ease, border-color 80ms ease; } .v2-root button.v2-chat__new-pod-action:hover { background: var(--v2-surface-hover); } .v2-root button.v2-chat__new-pod-action--hosted { background: var(--v2-ink); color: var(--v2-on-ink); font-weight: 600; } .v2-root button.v2-chat__new-pod-action--hosted:hover { background: var(--v2-ink-hover); } .v2-root button.v2-chat__new-pod-action--hosted:disabled { opacity: 0.7; } .v2-chat__new-pod-action-title { color: var(--v2-text-primary); font-size: 13px; font-weight: 700; } .v2-chat__new-pod-action-text, .v2-chat__new-pod-status { color: var(--v2-text-secondary); font-size: 11px; line-height: 1.4; } .v2-chat__new-pod-action--invite .v2-invite-link-row { width: 100%; margin-top: auto; } .v2-root button.v2-chat__new-pod-copy { flex: 0 0 auto; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-accent-text); font-size: 11px; font-weight: 700; } .v2-chat__new-pod-action--invite > .v2-chat__new-pod-copy { min-height: 32px; margin-top: auto; } @media (max-width: 760px) { .v2-chat__new-pod-action--invite > .v2-chat__new-pod-copy { min-height: 44px; } } .v2-root button.v2-chat__new-pod-copy:hover { background: var(--v2-surface-hover); } .v2-chat__new-pod-error { display: flex; align-items: center; gap: 8px; margin-top: auto; color: var(--v2-danger); font-size: 11px; } .v2-root .v2-chat__new-pod-error button { flex: 0 0 auto; color: var(--v2-accent-text); font-size: 11px; font-weight: 700; } .v2-root button.v2-chat__starter-prompt { min-width: 0; max-width: 100%; padding: 7px 11px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-pill); background: var(--v2-surface); color: var(--v2-text-secondary); font-size: 12px; font-weight: 600; line-height: 1.35; text-align: left; white-space: normal; transition: background 80ms ease, border-color 80ms ease, color 80ms ease; } .v2-root button.v2-chat__starter-prompt:hover { background: var(--v2-surface-hover); } @media (max-width: 700px) { .v2-chat__new-pod { padding: 16px; } .v2-chat__new-pod-actions { grid-template-columns: minmax(0, 1fr); } .v2-root button.v2-chat__new-pod-action, .v2-chat__new-pod-action { min-height: 0; } } .v2-chat__composer-input-wrap { position: relative; display: flex; align-items: flex-end; gap: 10px; min-height: 60px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); padding: 10px 10px 10px 12px; background: var(--v2-bg); transition: border-color 120ms ease, box-shadow 120ms ease; } .v2-chat__composer-input-wrap:focus-within { border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-chat__composer-input { flex: 1; min-height: 38px; max-height: 96px; padding: 0; border-radius: 0; border: none; background: transparent; font-size: 14px; line-height: 1.45; resize: vertical; outline: none; transition: background 80ms ease, border-color 80ms ease; } .v2-chat__composer-input:focus { border-color: transparent; background: transparent; } .v2-chat__composer-actions { display: flex; align-items: center; gap: 2px; padding: 0; align-self: flex-end; order: 2; } .v2-chat__composer-icon-btn { width: 32px; height: 32px; display: grid; place-items: center; border-radius: var(--v2-radius-sm); color: var(--v2-text-tertiary); font-size: 14px; transition: background 80ms ease, color 80ms ease; } .v2-chat__composer-icon-btn:hover { background: var(--v2-bg-subtle); color: var(--v2-text-primary); } /* Explicit root/button selector for the composer control; the global reset is deliberately a low-specificity default and must not own this state. */ .v2-root button.v2-chat__send { width: 36px; height: 36px; display: grid; place-items: center; border-radius: 9px; background: var(--v2-ink); border-color: var(--v2-ink); color: var(--v2-on-ink); transition: background 80ms ease; flex-shrink: 0; order: 3; } .v2-chat__composer-input { order: 1; } .v2-root button.v2-chat__send--execute { background: var(--v2-ink); border-color: var(--v2-ink); } .v2-root button.v2-chat__send--execute:hover { background: var(--v2-ink-hover); } .v2-root button.v2-chat__send:hover { background: var(--v2-ink-hover); } .v2-root button.v2-chat__send:disabled { background: var(--v2-border-strong); cursor: not-allowed; } .v2-chat__composer-footer { height: 18px; padding-top: 0; margin-top: 5px; font-size: 11px; color: var(--v2-text-muted); display: flex; align-items: center; gap: 4px; justify-content: center; } .v2-chat__composer-footer-link { color: var(--v2-text-secondary); font-weight: 600; text-decoration: underline; } .v2-chat__composer-error { color: var(--v2-danger); font-weight: 600; } /* Composer hint row — keyboard affordances below the input wrap. Mirrors the .composer__hint pattern in components-composer.html. */ .v2-chat__composer-hint { display: flex; align-items: center; justify-content: space-between; margin-top: 6px; padding: 0 4px; font-size: 11px; color: var(--v2-text-muted); } .v2-chat__composer-hint kbd { font-family: var(--v2-font-mono); font-size: 10.5px; font-weight: 600; color: var(--v2-text-tertiary); background: var(--v2-surface-hover); border: 1px solid var(--v2-border-soft); border-radius: 4px; padding: 1px 5px; margin: 0 2px; } /* Read-only banner shown in place of the composer when the viewer can read an agent-dm pod (§3.7) but isn't a formal member. Styled as a soft note, not an error — being a read-only observer is the intended state. */ .v2-chat__readonly { display: flex; align-items: flex-start; gap: 12px; padding: 14px 16px; margin: 12px 16px 16px; background: var(--v2-bg-subtle); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); } .v2-chat__readonly-icon { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: var(--v2-radius-pill); background: var(--v2-surface-hover); color: var(--v2-ink); } .v2-chat__readonly-body { flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; } .v2-chat__readonly-title { font-size: 13px; font-weight: 600; color: var(--v2-text-primary); } .v2-chat__readonly-text { font-size: 12.5px; line-height: 1.45; color: var(--v2-text-secondary); } /* TASK-406: quiet, non-interactive kernel action line in the pod timeline. */ .v2-system-action-line { box-sizing: border-box; width: calc(100% - 36px); margin-left: 36px; display: grid; grid-template-columns: 16px minmax(0, max-content) auto minmax(0, 1fr) auto; align-items: center; gap: 8px; padding: 4px 0; font: 400 13px/16px var(--v2-font); } .v2-thread .v2-system-action-line .v2-avatar { width: 16px; height: 16px; border-width: 1px; font: 650 11px/1 var(--v2-font-mono); letter-spacing: 0; text-indent: 0; } .v2-system-action-line__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--v2-text-primary); font-weight: 500; } .v2-system-action-line__action { grid-column: 3; display: flex; gap: 5px; min-width: 0; overflow: hidden; white-space: nowrap; } .v2-system-action-line__verb { color: var(--v2-text-tertiary); } .v2-system-action-line__object { min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--v2-text-tertiary); font: 400 11px/16px var(--v2-font-mono); } .v2-system-action-line time { grid-column: 5; color: var(--v2-text-placeholder); font: 400 11px/16px var(--v2-font-mono); } /* A run of claim lines folds to one row. The toggle is a control, so it carries the same chevron pattern as the long-message Show more. */ .v2-root button.v2-claim-run__toggle { display: inline-flex; align-items: center; gap: 5px; height: 24px; margin: 4px 0; padding: 0 8px; border: 0; border-radius: 7px; background: var(--v2-surface); color: var(--v2-text-secondary); box-shadow: inset 0 0 0 1px var(--v2-border); font: 500 12px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-claim-run__toggle:hover { background: var(--v2-surface-hover); } .v2-root button.v2-claim-run__toggle:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--v2-accent-text); } .v2-claim-run__toggle::after { content: ''; width: 6px; height: 6px; margin-left: 2px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg) translateY(-2px); transition: transform 160ms; } .v2-claim-run__toggle[aria-expanded='true']::after { transform: rotate(225deg) translateY(-2px); } /* §3.8 system event card — replaces the regular author/avatar bubble for commonly-bot announcements like "Pixel and codex started a DM". One-row, chrome-light, with a primary CTA that navigates internally. */ .v2-msg.v2-msg--system { /* Override the two-column avatar grid from .v2-msg: a system card is a single child and would otherwise be crammed into the 38px avatar column, collapsing the headline and wrapping the timestamp. Block = full width. Selector MUST be `.v2-msg.v2-msg--system` (two classes): `.v2-msg` sets `display: grid` LATER in this file, so an equal-specificity `.v2-msg--system` loses on source order. Higher specificity wins regardless of order. */ display: block; padding: 6px 0; } .v2-syscard { display: flex; align-items: center; gap: 12px; padding: 10px 14px; background: var(--v2-surface-hover); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); } .v2-syscard--action { background: var(--v2-surface); box-shadow: 0 0 0 2px var(--v2-accent); } .v2-syscard__icon { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: var(--v2-radius-pill); background: var(--v2-surface-hover); color: var(--v2-ink); } .v2-syscard__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; } .v2-syscard__headline { font-size: 13px; font-weight: 600; color: var(--v2-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-syscard__time { font-size: 11.5px; color: var(--v2-text-secondary); } .v2-root button.v2-syscard__cta, .v2-syscard__cta { flex: 0 0 auto; font-size: 12.5px; font-weight: 600; color: var(--v2-on-ink); background: var(--v2-ink); border: 1px solid var(--v2-ink); border-radius: var(--v2-radius-pill); padding: 6px 14px; cursor: pointer; transition: background 120ms ease; } .v2-root button.v2-syscard__cta:hover, .v2-syscard__cta:hover { background: var(--v2-ink-hover); } /* GitHub PR preview card. Rendered below a message body when the content contains a `https://github.com///pull/` URL. Card fetches from GitHub REST API on mount; failure mode is silent (parent's clickable URL stays). Visual: borders not shadows, one accent color, no gradients — matches the v2 design system. */ .v2-prcard { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; padding: 10px 12px; background: var(--v2-surface); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); text-decoration: none; color: var(--v2-text-primary); transition: border-color 120ms ease, background 120ms ease; } .v2-prcard:hover { border-color: var(--v2-border); background: var(--v2-surface-hover); } .v2-prcard--loading { flex-direction: row; align-items: center; justify-content: space-between; gap: 8px; color: var(--v2-text-secondary); font-size: 12.5px; } .v2-prcard__chip { font-family: var(--v2-font-mono, ui-monospace, SFMono-Regular, monospace); font-size: 12px; padding: 2px 8px; border-radius: var(--v2-radius-pill); background: var(--v2-accent-soft); color: var(--v2-accent-text); } .v2-prcard__loading-text { font-style: italic; } .v2-prcard__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; color: var(--v2-text-secondary); } .v2-prcard__repo { font-family: var(--v2-font-mono, ui-monospace, SFMono-Regular, monospace); letter-spacing: 0.01em; } .v2-prcard__state { display: inline-flex; align-items: center; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; padding: 2px 8px; border-radius: var(--v2-radius-pill); border: 1px solid transparent; } .v2-prcard__state--open { color: #16a34a; background: rgba(22, 163, 74, 0.10); border-color: rgba(22, 163, 74, 0.20); } .v2-prcard__state--merged { color: #6f42c1; background: rgba(111, 66, 193, 0.10); border-color: rgba(111, 66, 193, 0.20); } .v2-prcard__state--closed { color: #ef4444; background: rgba(239, 68, 68, 0.10); border-color: rgba(239, 68, 68, 0.20); } .v2-prcard__title { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--v2-text-primary); } .v2-prcard__num { font-family: var(--v2-font-mono, ui-monospace, SFMono-Regular, monospace); color: var(--v2-text-secondary); font-weight: 500; margin-right: 4px; } .v2-prcard__meta { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; font-size: 12px; color: var(--v2-text-secondary); } .v2-prcard__metric { font-family: var(--v2-font-mono, ui-monospace, SFMono-Regular, monospace); font-size: 11.5px; } .v2-prcard__metric--add { color: #16a34a; } .v2-prcard__metric--del { color: #ef4444; } .v2-prcard__contributors { display: inline-flex; align-items: center; margin-left: auto; } .v2-prcard__avatar { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; margin-left: -6px; border-radius: 50%; background-size: cover; background-position: center; background-color: var(--v2-accent-soft); border: 2px solid var(--v2-surface); font-size: 10px; font-weight: 600; color: var(--v2-accent-text); } .v2-prcard__avatar:first-child { margin-left: 0; } .v2-prcard__avatar--overflow { background-color: var(--v2-border-soft); color: var(--v2-text-secondary); font-size: 10px; } /* @-mention dropdown anchored to the composer input wrap. Sits above the composer in DOM order but renders above-and-out via absolute positioning. */ .v2-mention-dropdown { position: absolute; left: 0; right: 0; bottom: calc(100% + 6px); z-index: 10; max-height: 240px; overflow-y: auto; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: var(--v2-radius); box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12); padding: 4px; display: flex; flex-direction: column; gap: 2px; } .v2-mention-item { display: flex; align-items: center; gap: 10px; padding: 7px 9px; border-radius: var(--v2-radius-sm); background: transparent; border: none; text-align: left; cursor: pointer; width: 100%; font: inherit; color: var(--v2-text-primary); } .v2-mention-item:hover, .v2-mention-item--active { background: var(--v2-surface-hover); } /* Keep an explicit root/button selector for the interaction states. The reset is a low-specificity default now, but these rules document the intended highlight instead of relying on source order or browser defaults. */ .v2-root button.v2-mention-item:hover { background: var(--v2-surface-hover); } .v2-root button.v2-mention-item--active { background: var(--v2-surface-hover); } /* The dropdown owns the item's 7px 9px padding explicitly. */ .v2-root .v2-mention-dropdown button.v2-mention-item { padding: 7px 9px; } .v2-mention-item__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; } .v2-mention-item__label { font-size: 13px; font-weight: 600; color: var(--v2-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-mention-item__sub { font-size: 11px; color: var(--v2-text-tertiary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ---------- Message bubble ---------- */ .v2-msg { display: grid; grid-template-columns: 38px minmax(0, 1fr); align-items: start; gap: 12px; padding: 10px 0; } /* Consecutive-author grouping (craft baseline rule 3): grouped rows drop the 22px head + avatar and tighten padding, so a run of messages from one author reads as one block. The ghost keeps the grid's avatar column so text alignment never shifts. Reply and Thread become hover affordances pinned to the row's top-right, since the head row is gone. */ .v2-msg--grouped { padding: 2px 0; } .v2-msg__avatar-ghost { width: 38px; } /* The message action cluster (taste rulings 2026-08-23): Reply, Thread, and the reaction trigger share ONE floating pill at the row's top-right, identical for headed and grouped rows. Absolute + hover means zero layout shift; icon buttons instead of text keep it quiet at rest and compact under the cursor. The reaction picker anchors to the cluster so the trigger sits with its siblings instead of orphaned in an empty band below the message (the old absolute "+"). */ .v2-msg { position: relative; } .v2-msg__actions { position: absolute; top: -12px; right: 8px; display: flex; align-items: center; gap: 1px; padding: 2px; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: 8px; box-shadow: 0 1px 4px rgba(16, 20, 30, 0.08); opacity: 0; pointer-events: none; transition: opacity 0.1s ease; z-index: 6; } .v2-msg:hover .v2-msg__actions, .v2-msg__actions:focus-within { opacity: 1; pointer-events: auto; } .v2-root button.v2-msg__action { appearance: none; border: none; background: transparent; color: var(--v2-text-secondary); width: 26px; height: 26px; border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; } .v2-root button.v2-msg__action:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-msg__action-wrap { position: relative; display: inline-flex; } .v2-msg__actions .v2-msg__reaction-picker { position: absolute; top: calc(100% + 6px); bottom: auto; right: 0; left: auto; } .v2-msg__body { flex: 1; min-width: 0; } .v2-msg__head { display: flex; align-items: center; gap: 7px; height: 22px; margin-bottom: 0; } .v2-msg__author { font-size: 13px; font-weight: 700; color: var(--v2-text-primary); } .v2-msg__author-btn { appearance: none; background: transparent; border: none; padding: 0; font-size: 13px; font-weight: 700; color: var(--v2-text-primary); cursor: pointer; border-radius: 4px; transition: color 80ms ease; } .v2-msg__author-btn:hover { background: var(--v2-surface-hover); } .v2-msg__author-kind { display: inline-block; height: 16px; padding: 0 5px; border-radius: 3px; background: var(--v2-surface-hover); color: var(--v2-accent-text); font: 700 11px/16px var(--v2-font-mono); letter-spacing: 0.02em; } .v2-msg__avatar-btn { appearance: none; background: transparent; border: none; padding: 0; cursor: pointer; border-radius: 50%; display: inline-grid; place-items: center; width: fit-content; height: fit-content; line-height: 0; transition: box-shadow 100ms ease; } .v2-msg__avatar-btn:hover { background: var(--v2-surface-hover); } .v2-msg__lead-badge { background: transparent; color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); height: 18px; font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 4px; text-transform: uppercase; letter-spacing: 0.04em; } .v2-msg__time { font-size: 11px; color: var(--v2-text-tertiary); } .v2-msg__content { font-size: 14px; line-height: 1.55; color: var(--v2-message-text); margin-top: 3px; word-break: break-word; /* NO measure cap — the THIRD ruling on this (2026-08-24 full-width Slack model; #1367's craft-audit 75ch reverted 2026-09-01 by explicit request: "I still don't like the char limit, looks really bad on desktop"). Typographic best practice loses to the product decision here; the invariants test now bans ch-unit max-widths on message content so an audit can't re-litigate this silently. */ } .v2-msg__content > *:first-child { margin-top: 0; } .v2-msg__content > *:last-child { margin-bottom: 0; } .v2-msg__content p { margin: 0 0 6px; white-space: pre-wrap; } .v2-msg__content a { color: var(--v2-accent-text); text-decoration: underline; } .v2-msg__mention { background: transparent; color: var(--v2-accent-text); padding: 1px 5px; border-radius: 5px; font-weight: 500; white-space: nowrap; } /* A mention is a tinted system signal, not a separate card or accent rail. */ .v2-msg--mention { background: var(--v2-surface-hover); border-radius: var(--v2-radius-sm); padding: 8px 10px 8px 10px; } /* The wash bleeds one padding past the row on BOTH sides so the mention TEXT sits exactly on the shared grid like every other row ( 2026-08-23 — mentions sat off-grid while messages aligned; the old bleed was -12px against 10px padding, 2px off). The bleed lands inside the pane's 24px gutter. 0-2-0 beats the `> *` width rule regardless of source order. */ .v2-chat__messages > .v2-msg--mention { width: calc(100% + 20px); margin-inline: -10px; } .v2-msg__content ul, .v2-msg__content ol { margin: 4px 0 6px; padding-left: 22px; } .v2-msg__content li { margin: 2px 0; } .v2-msg__content code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; background: var(--v2-surface-tint); padding: 1px 5px; border-radius: 4px; } .v2-msg__content pre { margin: 6px 0; padding: 10px 12px; background: var(--v2-surface-tint); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); overflow-x: auto; font-size: 12.5px; line-height: 1.5; } .v2-msg__content pre code { background: transparent; padding: 0; font-size: inherit; } .v2-msg__content blockquote { margin: 6px 0; padding: 2px 0 2px 10px; border-left: 3px solid var(--v2-border); color: var(--v2-text-secondary); font-style: italic; } .v2-msg__content h1, .v2-msg__content h2, .v2-msg__content h3 { margin: 8px 0 4px; font-weight: 700; } .v2-msg__content h1 { font-size: 15px; } .v2-msg__content h2 { font-size: 14.5px; } .v2-msg__content h3 { font-size: 14px; } .v2-msg__content hr { border: none; border-top: 1px solid var(--v2-border-soft); margin: 8px 0; } .v2-msg__content strong { font-weight: 700; } .v2-msg__content em { font-style: italic; } .v2-msg__image-link { display: inline-block; margin-top: 7px; max-width: min(420px, 100%); border-radius: var(--v2-radius); overflow: hidden; border: 1px solid var(--v2-border); background: var(--v2-surface); } .v2-msg__image { display: block; max-width: 100%; max-height: 320px; object-fit: contain; } .v2-msg__file { width: 300px; height: 40px; display: inline-grid; grid-template-columns: 28px minmax(0, 1fr) auto; align-items: center; gap: 9px; padding: 0 12px; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); margin-top: 7px; max-width: 100%; } .v2-msg__file-icon { width: 28px; height: 28px; border-radius: 6px; display: grid; place-items: center; font-size: 10px; font-weight: 700; color: #fff; } .v2-msg__file-meta { display: flex; flex-direction: column; font-size: 12px; min-width: 0; } .v2-msg__file-name { color: #374151; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-msg__file-size { color: var(--v2-text-tertiary); font-size: 11px; } .v2-msg__reactions { display: flex; gap: 6px; margin-top: 6px; } .v2-msg__reaction { display: inline-flex; align-items: center; gap: 4px; height: 26px; padding: 0 9px; border-radius: var(--v2-radius-sm); background: var(--v2-surface); font-size: 12px; color: var(--v2-text-secondary); border: 1px solid transparent; transition: background 80ms ease, border-color 80ms ease; } .v2-msg__reaction:hover { background: var(--v2-surface-hover); } /* ---------- Inspector ---------- */ .v2-inspector { height: 100%; overflow-y: auto; display: flex; flex-direction: column; gap: 0; position: relative; } .v2-inspector { display: flex; flex-direction: column; height: 100%; } .v2-inspector__header { position: relative; padding: 18px 44px 16px 18px; border-bottom: 1px solid var(--v2-border-soft); flex-shrink: 0; } .v2-inspector__pod-head { display: flex; align-items: flex-start; gap: 12px; } .v2-inspector__pod-block { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; } .v2-inspector__pod-name { font-size: 16px; font-weight: 700; color: var(--v2-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-inspector__pod-meta { font-size: 12px; color: var(--v2-text-tertiary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-inspector__sub-title { font-size: 14px; font-weight: 650; color: var(--v2-text-primary); margin-top: 4px; } .v2-inspector__back { appearance: none; background: transparent; border: none; display: inline-flex; align-items: center; gap: 4px; padding: 4px 6px; margin: -4px 0 6px -6px; font-size: 12.5px; font-weight: 600; color: var(--v2-text-tertiary); cursor: pointer; border-radius: var(--v2-radius-sm); transition: color 80ms ease, background 80ms ease; } .v2-inspector__back:hover { color: var(--v2-text-primary); background: var(--v2-surface-hover); } .v2-inspector__close { position: absolute; top: 14px; right: 12px; width: 24px; height: 24px; display: grid; place-items: center; border-radius: var(--v2-radius-sm); color: var(--v2-text-tertiary); background: transparent; border: none; cursor: pointer; transition: background 80ms ease, color 80ms ease; } .v2-inspector__close:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-inspector__body { flex: 1; overflow-y: auto; padding: 14px 14px 24px; background: var(--v2-surface-tint); } /* Pill tabs — see frontend/design-system/preview/components-tabs.html. Used inside the inspector to split Overview / Members / Tasks without underline-tab competing with the chat header divider. */ .v2-inspector__tabs { display: inline-flex; gap: 4px; padding: 4px; background: var(--v2-bg); border: 1px solid var(--v2-border-soft); border-radius: 9px; margin: 0 0 12px; width: 100%; box-sizing: border-box; } .v2-root button.v2-inspector__tab { flex: 1 1 0; min-width: 0; height: 28px; padding: 0 6px; border-radius: 6px; background: transparent; border: none; font-size: 12px; font-weight: 600; letter-spacing: -0.005em; color: var(--v2-text-secondary); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: background 80ms ease, color 80ms ease, box-shadow 80ms ease; } .v2-root button.v2-inspector__tab:hover { color: var(--v2-text-primary); } .v2-root button.v2-inspector__tab--active { border-bottom: 2px solid var(--v2-accent); background: transparent; color: var(--v2-ink); font-weight: 600; } .v2-inspector__tab-count { height: 16px; min-width: 16px; padding: 0 5px; border-radius: 999px; background: var(--v2-border-soft); color: var(--v2-text-tertiary); font-size: 11px; font-family: var(--v2-font-mono); font-weight: 700; display: inline-flex; align-items: center; justify-content: center; } .v2-root button.v2-inspector__tab--active .v2-inspector__tab-count { background: transparent; color: var(--v2-ink); } /* NOW card — currently-active agent + task. Now lives inside .v2-inspector__section (which provides the card chrome). */ .v2-inspector__now { display: flex; flex-direction: column; gap: 8px; } .v2-inspector__now-eyebrow { font-size: 11px; font-weight: 700; color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); letter-spacing: 0.12em; text-transform: uppercase; } /* Pod-progress card — overall task completion bar. Surfaces only when the pod has at least one tracked task. */ .v2-inspector__progress-row { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; } .v2-inspector__progress-stat { font-size: 13px; font-weight: 600; color: var(--v2-text-primary); } .v2-inspector__progress-pct { font-size: 12px; font-weight: 600; color: var(--v2-ink); font-family: var(--v2-font-mono); font-variant-numeric: tabular-nums; } .v2-inspector__progress-track { height: 6px; border-radius: 3px; background: var(--v2-border-soft); overflow: hidden; } .v2-inspector__progress-bar { height: 100%; border-radius: 3px; background: var(--v2-ink); transition: width 240ms ease; } /* Danger zone — destructive actions (delete pod, etc.) live in the Manage tab inside this red-accent card with proper warning chrome. */ .v2-inspector__danger { border-color: rgba(239, 68, 68, 0.25); background: rgba(239, 68, 68, 0.04); } .v2-inspector__danger-title { font-size: 13px; font-weight: 700; color: var(--v2-danger); margin-bottom: 4px; } .v2-inspector__danger-text { font-size: 12px; color: var(--v2-text-secondary); margin-bottom: 12px; line-height: 1.5; } .v2-root button.v2-inspector__btn--danger { background: transparent; border-color: var(--v2-danger); color: var(--v2-danger); } .v2-root button.v2-inspector__btn--danger:hover { background: var(--v2-danger); color: var(--v2-on-accent); border-color: var(--v2-danger); } .v2-inspector__now-title { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 700; color: var(--v2-text-primary); letter-spacing: -0.01em; } .v2-inspector__now-pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--v2-success); box-shadow: 0 0 0 0 var(--v2-success-ring-strong); animation: v2-now-pulse var(--motion-pulse) var(--motion-ease-state) infinite; flex-shrink: 0; } @keyframes v2-now-pulse { 0% { box-shadow: 0 0 0 0 var(--v2-success-ring); } 70% { box-shadow: 0 0 0 6px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } } .v2-inspector__now-meta { font-size: 12px; color: var(--v2-text-secondary); line-height: 1.45; } /* Card-style sections inside the tinted inspector body — replaces the flat divider treatment. Mirrors the .card pattern in components-inspector.html. */ .v2-inspector__section { padding: 14px; background: var(--v2-bg); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); margin-bottom: 10px; } .v2-inspector__section:last-child { margin-bottom: 0; } /* "Quiet" sections have no card chrome — used for inline action rows like the "Manage" link on the Members tab and the danger zone. */ .v2-inspector__section--quiet { padding: 0; background: transparent; border: none; border-radius: 0; } .v2-inspector__section-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; } /* Eyebrow style — must read as a label, not body text. Mirrors the --c-fg-tertiary uppercase pattern in the design-system preview cards (see frontend/design-system/preview/components-inspector.html .eyebrow). */ .v2-inspector__section-title { font-size: 11px; font-family: var(--v2-font-mono); font-weight: 700; color: var(--v2-text-tertiary); letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 8px; } .v2-inspector__section-head .v2-inspector__section-title { margin-bottom: 0; } .v2-inspector__goal-text { font-size: 13px; line-height: 1.5; color: var(--v2-text-secondary); } .v2-inspector__empty { font-size: 12px; line-height: 1.5; color: var(--v2-text-tertiary); padding: 6px 0; } .v2-inspector__link { appearance: none; background: transparent; border: none; font-size: 13px; font-weight: 600; color: var(--v2-accent); cursor: pointer; padding: 0; } .v2-inspector__link:hover { text-decoration: underline; } .v2-inspector__link--block { display: inline-block; margin-top: 12px; font-size: 13px; } .v2-inspector__link--danger { color: var(--v2-danger); font-weight: 500; font-size: 12px; } .v2-inspector__link--danger:hover { color: var(--v2-danger); } /* ---------- Members section action row (Invite / Manage) ---------- * Replaces the bare text-link buttons that previously sat right-aligned * above the member list. Now reads as a proper action toolbar with a * primary "Invite" CTA (filled ink) and a secondary "Manage" affordance * (outline). Matches the "+ Add" / Cancel pattern used in Artifacts. */ .v2-inspector__members-actions { display: flex; gap: 6px; margin-bottom: 10px; } .v2-root button.v2-inspector__action, .v2-inspector__action { display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 11px; border-radius: 999px; border: 1px solid var(--v2-border-soft); background: var(--v2-surface); color: var(--v2-text-secondary); font-size: 12px; font-weight: 600; cursor: pointer; transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease; } .v2-root button.v2-inspector__action:hover, .v2-inspector__action:hover { background: var(--v2-bg-subtle); color: var(--v2-text-primary); border-color: var(--v2-border); } .v2-root button.v2-inspector__action--primary, .v2-inspector__action--primary { background: var(--v2-ink); border-color: var(--v2-ink); color: var(--v2-on-ink); flex: 1; justify-content: center; } .v2-root button.v2-inspector__action--primary:hover, .v2-inspector__action--primary:hover { background: var(--v2-ink-hover); } /* ---------- Inspector: Artifacts ---------- */ .v2-inspector__artifacts { display: flex; flex-direction: column; gap: 4px; } .v2-inspector__artifact-row { width: 100%; display: grid; grid-template-columns: 32px minmax(0, 1fr); align-items: center; gap: 10px; padding: 8px 0; background: transparent; border: none; text-align: left; cursor: pointer; border-radius: var(--v2-radius-sm); transition: background 80ms ease; } .v2-inspector__artifact-row:hover { background: var(--v2-surface-hover); } .v2-inspector__artifact-icon { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 8px; background: var(--v2-surface-hover); color: var(--v2-ink); font-size: 12px; font-weight: 700; text-transform: uppercase; } .v2-inspector__artifact-icon--lg { width: 48px; height: 48px; font-size: 18px; border-radius: 12px; } .v2-inspector__artifact-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .v2-inspector__artifact-title { font-size: 13px; font-weight: 600; color: var(--v2-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-inspector__artifact-sub { font-size: 11px; font-family: var(--v2-font-mono); color: var(--v2-text-tertiary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ---------- Inspector: Members ---------- */ /* Agent rows are buttons, so keep their row treatment explicit rather than relying on the global default reset. */ .v2-root button.v2-inspector__member-row, .v2-inspector__member-row { width: 100%; display: grid; grid-template-columns: 32px minmax(0, 1fr) auto; align-items: center; gap: 12px; padding: 10px 8px; margin: 0 -8px; background: transparent; border: none; text-align: left; cursor: pointer; border-radius: var(--v2-radius-sm); transition: background 80ms ease; } .v2-inspector__member-row + .v2-inspector__member-row, .v2-inspector__member-row + .v2-inspector__member-row--static { margin-top: 4px; } .v2-inspector__member-meta { gap: 3px; } .v2-root button.v2-inspector__member-row:hover, .v2-inspector__member-row:hover { background: var(--v2-surface-hover); } .v2-inspector__member-row--static { cursor: default; } .v2-inspector__member-row--static:hover { background: transparent; } .v2-inspector__member-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .v2-inspector__member-name { font-size: 13px; font-weight: 600; color: var(--v2-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-inspector__member-role { font-size: 12px; color: var(--v2-text-tertiary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ---------- Inspector: Run State ---------- */ .v2-inspector__runstate { display: flex; flex-direction: column; gap: 8px; } .v2-inspector__runstate-row { display: flex; align-items: center; justify-content: space-between; font-size: 13px; color: var(--v2-text-secondary); } .v2-inspector__runstate-label { font-weight: 500; } .v2-inspector__pill { height: 22px; padding: 0 10px; display: inline-flex; align-items: center; border-radius: 999px; font-size: 11px; font-family: var(--v2-font-mono); font-weight: 600; letter-spacing: 0.01em; } .v2-inspector__pill--blocked { background: rgba(239, 68, 68, 0.10); color: #b91c1c; } .v2-inspector__pill--progress { border: 1px solid var(--v2-ink); background: transparent; color: var(--v2-ink); font-family: var(--v2-font-mono); } .v2-inspector__pill--complete { background: rgba(16, 185, 129, 0.12); color: #047857; } .v2-inspector__task-list { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; } .v2-inspector__section-subtitle { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--v2-text-muted); margin-bottom: 2px; } .v2-inspector__task-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 10px; background: var(--v2-bg-subtle); border: 1px solid var(--v2-border); border-radius: var(--v2-radius); } .v2-inspector__task-title { font-size: 13px; color: var(--v2-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; min-width: 0; } .v2-inspector__task-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; } .v2-inspector__task-assignee { font-size: 11px; color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); } /* ---------- Inspector: Detail sub-page ---------- */ .v2-inspector__detail { display: flex; flex-direction: column; gap: 14px; padding-top: 4px; } .v2-inspector__detail-head { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding-bottom: 8px; border-bottom: 1px solid var(--v2-border-soft); } .v2-inspector__detail-name { font-size: 18px; font-weight: 700; color: var(--v2-text-primary); letter-spacing: -0.01em; margin-top: 4px; } .v2-inspector__detail-sub { font-size: 12px; color: var(--v2-text-tertiary); display: flex; align-items: center; gap: 6px; } .v2-inspector__detail-actions { display: flex; gap: 8px; flex-wrap: wrap; } /* * Keep the explicit button selector for the inspector actions so their * bg/border/padding remain component-owned. The global reset is intentionally * low-specificity now; the `a.X` selector covers the artifact "Open" link * variant. */ .v2-root button.v2-inspector__btn, .v2-root a.v2-inspector__btn { appearance: none; height: 32px; padding: 0 14px; border-radius: var(--v2-radius-sm); border: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; transition: background 80ms ease, color 80ms ease, border-color 80ms ease; } .v2-root button.v2-inspector__btn:hover, .v2-root a.v2-inspector__btn:hover { color: var(--v2-text-primary); background: var(--v2-surface-hover); } .v2-root button.v2-inspector__btn--primary, .v2-root a.v2-inspector__btn--primary { background: var(--v2-ink); color: var(--v2-on-ink); border-color: var(--v2-ink); } .v2-root button.v2-inspector__btn--primary:hover, .v2-root a.v2-inspector__btn--primary:hover { background: var(--v2-ink-hover); } .v2-inspector__detail-card { display: flex; flex-direction: column; gap: 4px; } .v2-inspector__detail-kicker { font-size: 11px; font-family: var(--v2-font-mono); font-weight: 700; color: var(--v2-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; } .v2-inspector__detail-body { font-size: 13px; line-height: 1.5; color: var(--v2-text-secondary); } .v2-inspector__chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; } .v2-inspector__chip { height: 22px; padding: 0 10px; border-radius: 999px; background: var(--v2-surface-hover); color: var(--v2-text-secondary); font-size: 11px; font-family: var(--v2-font-mono); font-weight: 600; display: inline-flex; align-items: center; } /* Sprint B1: agent-DM list under member-detail. Clickable rows that * navigate to the DM pod (read-only for the human via the §3.7 * co-pod-member rule). Same visual rhythm as detail-card content; the * arrow glyph signals "this is interactive." */ .v2-inspector__dm-list { display: flex; flex-direction: column; gap: 4px; margin-top: 2px; } .v2-root button.v2-inspector__dm-row { display: flex; align-items: center; justify-content: space-between; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--v2-border-subtle); background: var(--v2-surface); color: var(--v2-text-primary); font-size: 13px; cursor: pointer; text-align: left; transition: background 0.12s ease, border-color 0.12s ease; } .v2-root button.v2-inspector__dm-row:hover { background: var(--v2-surface-hover); border-color: var(--v2-border); } .v2-inspector__dm-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-inspector__dm-arrow { color: var(--v2-text-tertiary); font-weight: 500; margin-left: 8px; } /* ---------- Runtime badge (driver tag — OC, CX, CC, WH, NA) ---------- * Identity (runtimeType) renders as the main pill; host=byo adds a small * "BYO" tag alongside. Cloud is the implicit default and stays unmarked * to keep the chrome quiet. Same pattern in compact form on the member- * list row (`.v2-runtime-mono` + `.v2-runtime-mono--byo`). */ .v2-inspector__detail-runtime { margin-top: 8px; display: flex; justify-content: center; align-items: center; gap: 6px; } .v2-runtime-pill { display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 9px 0 6px; border-radius: 999px; border: 1px solid var(--v2-border-soft); background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-size: 11px; font-weight: 600; letter-spacing: 0.01em; } .v2-runtime-pill__mono { font-size: 10px; font-weight: 700; letter-spacing: 0.04em; color: var(--v2-text-primary); background: var(--v2-surface); border: 1px solid var(--v2-border-soft); border-radius: 4px; padding: 1px 4px; line-height: 1; } .v2-runtime-pill__label { line-height: 1; } .v2-runtime-mono { display: inline-flex; align-items: center; justify-content: center; gap: 3px; height: 18px; min-width: 22px; padding: 0 5px; margin-left: 6px; border-radius: 4px; border: 1px solid var(--v2-border-soft); background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-size: 9.5px; font-weight: 700; letter-spacing: 0.04em; flex-shrink: 0; } .v2-runtime-mono--byo { border-color: var(--v2-border); background: var(--v2-surface-hover); } .v2-runtime-mono__byo { font-size: 8.5px; font-weight: 700; letter-spacing: 0.06em; opacity: 0.78; } .v2-runtime-host { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border-radius: 4px; border: 1px solid var(--v2-border); background: var(--v2-surface-hover); color: var(--v2-text-secondary); font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; } /* Member-list row runtime chip — shows the FULL runtime label (Claude Code, * Codex, OpenClaw …) so identity reads at a glance, with BYO as a small * trailing tag when the user is hosting the runtime themselves. The mono * codes (CC / CX / OC) live on the detail-card pill where there's room * for both. */ .v2-runtime-row { display: inline-flex; align-items: center; gap: 4px; margin-left: 6px; flex-shrink: 0; } .v2-runtime-row__label { display: inline-flex; align-items: center; height: 18px; padding: 0 8px; border-radius: 999px; border: 1px solid var(--v2-border-soft); background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-size: 10.5px; font-weight: 600; letter-spacing: 0.01em; white-space: nowrap; } .v2-runtime-row__byo { display: inline-flex; align-items: center; height: 16px; padding: 0 5px; border-radius: 4px; border: 1px solid var(--v2-border); background: var(--v2-surface-hover); color: var(--v2-text-tertiary); font-size: 9px; font-weight: 700; letter-spacing: 0.06em; } /* ---------- Role chip (preset category — Development / Design / etc.) ---------- * Shown on the Your Team card and used as the role tag on agent profiles. * Neutral by design — categories don't get color codes; the text label is * enough. Kept compact to fit in the team-card name row without wrapping. */ .v2-role-chip { display: inline-flex; align-items: center; height: 18px; padding: 0 8px; border-radius: 999px; border: 1px solid var(--v2-border-soft); background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-size: 10.5px; font-weight: 600; letter-spacing: 0.01em; white-space: nowrap; flex-shrink: 0; } /* ---------- Your Team category tab bar ---------- */ /* ---------- Invite modal + redeem page ---------- */ .v2-modal__overlay { position: fixed; inset: 0; z-index: 100; background: rgba(15, 23, 42, 0.42); display: flex; align-items: center; justify-content: center; padding: 24px; } .v2-modal { width: min(560px, 100%); max-height: calc(100vh - 48px); overflow: auto; background: var(--v2-surface); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-md, 12px); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18); display: flex; flex-direction: column; } .v2-modal__head { display: flex; align-items: center; justify-content: space-between; padding: 16px 18px 12px; border-bottom: 1px solid var(--v2-border-soft); } .v2-modal__title { font-size: 14px; font-weight: 700; color: var(--v2-text-primary); } .v2-root button.v2-modal__close, .v2-modal__close { width: 28px; height: 28px; border-radius: 6px; border: none; background: transparent; color: var(--v2-text-secondary); font-size: 20px; line-height: 1; cursor: pointer; } .v2-root button.v2-modal__close:hover, .v2-modal__close:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-modal__tabs { display: flex; gap: 0; padding: 0 18px; border-bottom: 1px solid var(--v2-border-soft); } .v2-root button.v2-modal__tab, .v2-modal__tab { height: 36px; padding: 0 14px; border: none; background: transparent; color: var(--v2-text-secondary); font-size: 12px; font-weight: 600; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; } .v2-root button.v2-modal__tab:hover, .v2-modal__tab:hover { color: var(--v2-text-primary); } .v2-root button.v2-modal__tab--active, .v2-modal__tab--active { color: var(--v2-accent); border-bottom-color: var(--v2-accent); } .v2-modal__body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 12px; } .v2-modal__hint { font-size: 12px; color: var(--v2-text-secondary); margin: 0; line-height: 1.5; } .v2-modal__hint--muted { color: var(--v2-text-tertiary); font-size: 11px; } .v2-modal__error { font-size: 11px; color: var(--v2-danger); margin-top: 4px; } .v2-modal__section-title { font-size: 12px; font-weight: 700; color: var(--v2-text-primary); } .v2-invite-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; } .v2-invite-options__field { display: flex; flex-direction: column; gap: 5px; min-width: 0; font-size: 11px; font-weight: 600; color: var(--v2-text-secondary); } .v2-invite-options__select { width: 100%; height: 36px; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); font: inherit; font-weight: 500; outline: none; } .v2-invite-options__select:focus { border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-invite-link-row { display: flex; gap: 6px; align-items: stretch; } /* The Copy button inside the invite-link row inherits `width: 100%` from * the base `.v2-invite-card__cta` rule (which is meant for full-width * primary CTAs). Inside the row it needs to stay sized to its content so * the URL input gets the remaining flex space. Without this override the * input collapses to ~20px and the URL is invisible. */ .v2-root .v2-invite-link-row button.v2-invite-card__cta, .v2-invite-link-row .v2-invite-card__cta { width: auto; flex-shrink: 0; margin-top: 0; padding: 0 12px; } .v2-invite-link { flex: 1; min-width: 0; padding: 8px 10px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); background: var(--v2-bg-subtle); font-size: 11px; color: var(--v2-text-secondary); font-family: ui-monospace, SFMono-Regular, monospace; outline: none; } .v2-invite-link:focus { border-color: var(--v2-accent); } .v2-invite-manage { display: flex; flex-direction: column; gap: 8px; padding-top: 14px; margin-top: 4px; border-top: 1px solid var(--v2-border-soft); } .v2-invite-manage__empty { padding: 12px; border: 1px dashed var(--v2-border); border-radius: var(--v2-radius-sm); color: var(--v2-text-tertiary); font-size: 11px; text-align: center; } .v2-invite-manage__list { display: flex; flex-direction: column; gap: 8px; } .v2-invite-manage__item { min-width: 0; padding: 10px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); background: var(--v2-surface); } .v2-invite-manage__summary, .v2-invite-manage__meta { display: flex; justify-content: space-between; gap: 8px; min-width: 0; } .v2-invite-manage__summary { align-items: baseline; font-size: 11px; color: var(--v2-text-tertiary); } .v2-invite-manage__summary strong { overflow: hidden; color: var(--v2-text-primary); font-weight: 650; text-overflow: ellipsis; white-space: nowrap; } .v2-invite-manage__meta { flex-wrap: wrap; margin-top: 3px; color: var(--v2-text-secondary); font-size: 10px; } .v2-invite-manage__url { box-sizing: border-box; width: 100%; min-width: 0; margin-top: 8px; padding: 7px 9px; border: 1px solid var(--v2-border-soft); border-radius: 6px; background: var(--v2-bg-subtle); color: var(--v2-text-secondary); font-family: var(--v2-font-mono); font-size: 10px; outline: none; } .v2-invite-manage__url:focus { border-color: var(--v2-accent); } .v2-invite-manage__actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-top: 8px; } .v2-root button.v2-invite-manage__action, .v2-invite-manage__action { min-width: 0; height: 30px; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); color: var(--v2-text-primary); font-size: 11px; font-weight: 600; cursor: pointer; } .v2-root button.v2-invite-manage__action:hover, .v2-invite-manage__action:hover { background: var(--v2-surface-hover); } .v2-root button.v2-invite-manage__action--danger, .v2-invite-manage__action--danger { border-color: var(--v2-danger-soft); color: var(--v2-danger); } .v2-root button.v2-invite-manage__action--danger:hover, .v2-invite-manage__action--danger:hover { background: var(--v2-danger-soft); } .v2-root button.v2-invite-manage__action:disabled, .v2-invite-manage__action:disabled { opacity: 0.6; cursor: not-allowed; } @media (max-width: 480px) { .v2-verification-banner { grid-template-columns: minmax(0, 1fr) 44px; grid-template-areas: "content dismiss" "resend resend"; align-items: start; gap: 6px 8px; min-height: 0; padding: 8px 12px; font-size: 16px; } .v2-root button.v2-verification-banner__resend { justify-self: start; } /* Auth is a primary phone flow: 16px prevents Safari's focus zoom and a 44px target keeps signup usable with a thumb. */ .v2-login__input { min-height: 44px; font-size: 16px; } .v2-root button.v2-login__submit { min-height: 44px; font-size: 16px; } .v2-modal__overlay { padding: 12px; } .v2-invite-options { grid-template-columns: minmax(0, 1fr); } .v2-invite-link-row { flex-wrap: wrap; } .v2-root .v2-invite-link-row button.v2-invite-card__cta, .v2-invite-link-row .v2-invite-card__cta { width: 100%; height: 34px; } } /* Standalone redeem page — `/v2/invite/:token`. Centered card so the logged-in user lands on a focused, readable join surface. */ .v2-invite-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 32px; background: var(--v2-bg-subtle); } .v2-invite-card { width: min(420px, 100%); background: var(--v2-surface); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-md, 12px); padding: 28px 24px 24px; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; } .v2-invite-card--loading { color: var(--v2-text-secondary); font-size: 13px; } .v2-invite-card__title { margin-top: 4px; font-size: 18px; font-weight: 700; color: var(--v2-text-primary); } .v2-invite-card__description { font-size: 13px; color: var(--v2-text-secondary); line-height: 1.5; } .v2-invite-card__meta { font-size: 11px; color: var(--v2-text-tertiary); letter-spacing: 0.04em; text-transform: uppercase; } .v2-invite-card__error { font-size: 12px; color: var(--v2-danger); } .v2-root button.v2-invite-card__cta, .v2-invite-card__cta { width: 100%; height: 38px; border: none; border-radius: var(--v2-radius-sm); background: var(--v2-accent-fill); color: var(--v2-on-accent); font-size: 13px; font-weight: 600; cursor: pointer; margin-top: 8px; } .v2-root button.v2-invite-card__cta:hover, .v2-invite-card__cta:hover { filter: brightness(1.05); } .v2-root button.v2-invite-card__cta:disabled, .v2-invite-card__cta:disabled { opacity: 0.6; cursor: not-allowed; } .v2-root button.v2-invite-card__cta--secondary, .v2-invite-card__cta--secondary { background: var(--v2-surface); color: var(--v2-text-primary); border: 1px solid var(--v2-border-soft); } .v2-root button.v2-invite-card__cta--secondary:hover, .v2-invite-card__cta--secondary:hover { background: var(--v2-bg-subtle); } /* ---------- Avatar ---------- */ .v2-avatar { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; color: #fff; font-weight: 650; font-size: 11px; flex-shrink: 0; border: 2px solid var(--v2-surface); text-transform: uppercase; position: relative; /* Two initials at 700 with default tracking collide at 24px — the pair reads as one glyph. 650 with positive tracking separates them without making the avatar shout; the optical centre then sits ~0.5px right, so the tracking is compensated with an equal indent rather than left as a visible lean. */ letter-spacing: 0.04em; text-indent: 0.04em; /* The seeded gradient is the identity; a flat inner highlight over it reads as a lit sphere rather than a filled circle, and costs nothing. */ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), inset 0 -1px 0 rgba(0, 0, 0, 0.10); overflow: hidden; } /* A photo is the identity when one exists — the gradient underneath is only a backing plate for transparent PNGs, so the inner highlight must not sit on top of someone's face. */ .v2-avatar:has(img) { box-shadow: none; } /* Character tier gets a hairline ring (TASK-679). The compact transcript frame (--flat) stays unframed; the :has(img) rule above outranks a plain class, so the selector repeats it to win. */ .v2-avatar:has(img).v2-avatar--character:not(.v2-avatar--flat) { box-shadow: 0 0 0 1px var(--v2-avatar-frame); } .v2-avatar--lg { width: 34px; height: 34px; font-size: 12px; } .v2-avatar--md { width: 30px; height: 30px; font-size: 11px; } .v2-avatar--sm { width: 24px; height: 24px; font-size: 10px; } .v2-avatar__online { position: absolute; right: -1px; bottom: -1px; width: 9px; height: 9px; border-radius: 50%; background: var(--v2-success); border: 2px solid var(--v2-surface); } /* ---------- Login ---------- */ .v2-login { flex: 1; display: grid; place-items: center; background: var(--v2-bg); } .v2-login__card { width: 100%; max-width: 380px; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); padding: 32px 28px; box-shadow: var(--v2-shadow-lg); } .v2-login__brand { display: flex; align-items: center; gap: 10px; font-weight: 800; font-size: 18px; margin-bottom: 4px; } .v2-login__title { font-size: 22px; font-weight: 800; margin: 16px 0 4px; letter-spacing: -0.01em; } .v2-login__subtitle { font-size: 13px; color: var(--v2-text-secondary); margin-bottom: 22px; } .v2-login__field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; } .v2-login__label { font-size: 12px; font-weight: 600; color: var(--v2-text-secondary); } .v2-login__input { padding: 10px 12px; border-radius: var(--v2-radius); border: 1px solid var(--v2-border); background: var(--v2-surface); font-size: 14px; outline: none; transition: border-color 80ms ease; } .v2-login__input:focus { border-color: var(--v2-accent); } /* Keep the explicit root/button selector so the accent fill remains owned by the submit control (login + register). */ .v2-root button.v2-login__submit { width: 100%; margin-top: 8px; padding: 10px 14px; background: var(--v2-accent-fill); color: var(--v2-on-accent); font-weight: 700; font-size: 14px; border-radius: var(--v2-radius); transition: background 80ms ease; } .v2-root button.v2-login__submit:hover:not(:disabled) { background: var(--v2-accent-strong); } .v2-root button.v2-login__submit:disabled { background: var(--v2-border-strong); cursor: not-allowed; } .v2-login__error { margin-top: 10px; padding: 8px 12px; border-radius: var(--v2-radius); background: rgba(239, 68, 68, 0.1); color: var(--v2-danger); font-size: 12px; } .v2-login__forgot { margin-top: 8px; font-size: 12px; text-align: right; } /* "or" separator between password form and social buttons. NOT .v2-login__divider — that name is already taken by the invite-required page's bordered section break (defined later in this file, so it would win the cascade and stack a second hairline on top of this one). */ .v2-login__or { display: flex; align-items: center; gap: 10px; margin-top: 16px; color: var(--v2-text-tertiary); font-size: 12px; } .v2-login__or::before, .v2-login__or::after { content: ''; flex: 1; height: 1px; background: var(--v2-border); } .v2-login__oauth { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; } /* OAuth links and invite forms share one button treatment. Prefix with `.v2-root` to beat the global button/link rules. */ .v2-login__oauth-form { margin: 0; } .v2-root :where(a, button).v2-login__oauth-btn { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 10px 14px; border-radius: var(--v2-radius); border: 1px solid var(--v2-border-strong); background: var(--v2-surface); color: var(--v2-text-primary); font-weight: 600; font-size: 14px; text-decoration: none; cursor: pointer; transition: background 80ms ease, border-color 80ms ease; } .v2-root :where(a, button).v2-login__oauth-btn:hover { background: var(--v2-bg-subtle); border-color: var(--v2-accent); } /* Inline helper under a single field — plain small text, unlike the boxed .v2-login__hint. Born from the invite-code placeholder truncating. */ .v2-login__field-hint { display: block; margin-top: 6px; font-size: 12px; line-height: 1.45; color: var(--v2-text-tertiary); } .v2-login__hint { margin-top: 18px; padding: 10px 12px; border-radius: var(--v2-radius); background: var(--v2-bg-subtle); font-size: 12px; color: var(--v2-text-tertiary); } .v2-login__hint code { font-family: 'SF Mono', Menlo, monospace; background: var(--v2-surface); padding: 1px 5px; border-radius: 4px; border: 1px solid var(--v2-border); color: var(--v2-text-primary); } /* `.v2-root a { color: inherit }` (0,1,1) beats a single-class rule on specificity, so prefix to win. Same pattern as the v2-button reset. */ .v2-root a.v2-login__link { color: var(--v2-accent); text-decoration: none; font-weight: 500; } .v2-root a.v2-login__link:hover { text-decoration: underline; } /* Extra login-card affordances — used by the invite-required page, which stacks two forms (invite code + waitlist) in one card. A bare
picks up the dark global form background (V2Login/V2Register dodge this by putting the card class ON the single form); here the card is a
with two s inside, so neutralize the form background/box explicitly. */ .v2-login__card form { background: transparent; border: 0; padding: 0; margin: 0; box-shadow: none; } .v2-login__success { margin-top: 10px; padding: 8px 12px; border-radius: var(--v2-radius); background: var(--v2-success-soft); color: var(--v2-success); font-size: 12px; } .v2-root button.v2-login__submit--ghost { background: transparent; color: var(--v2-text-primary); border: 1px solid var(--v2-border); } .v2-root button.v2-login__submit--ghost:hover:not(:disabled) { background: var(--v2-surface-hover); border-color: var(--v2-border-strong); } .v2-login__divider { margin: 22px 0 14px; padding-top: 18px; border-top: 1px solid var(--v2-border-soft); font-size: 13px; font-weight: 600; color: var(--v2-text-secondary); text-align: left; } /* ---------- Empty / loading states ---------- */ .v2-feature { min-width: 0; background: var(--v2-surface); /* inside the card the ground is white; the card is the tint step */ } .v2-feature__header { flex-shrink: 0; padding: 22px 28px 18px; border-bottom: 1px solid var(--v2-border-soft); background: var(--v2-surface); } .v2-feature__title { margin: 0; color: var(--v2-text-primary); font-size: 24px; font-weight: 850; letter-spacing: -0.03em; } .v2-page-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; min-width: 0; } .v2-page-head__identity { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; min-width: 0; } .v2-page-head__identity h1 { min-width: 0; } .v2-page-head__meta { color: var(--v2-text-muted); font: 500 12px/16px var(--v2-font-mono); } .v2-page-head__actions { display: flex; align-items: center; gap: 8px; } .v2-hint { position: relative; display: inline-flex; align-items: center; flex: 0 0 auto; } .v2-root button.v2-hint__trigger { display: inline-grid; place-items: center; width: 18px; height: 18px; padding: 0; border: 1px solid var(--v2-border); border-radius: 50%; background: transparent; color: var(--v2-text-muted); font: 600 12px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-hint__trigger:hover { background: var(--v2-surface-hover); } .v2-root button.v2-hint__trigger:focus-visible { border-color: var(--v2-accent); outline: 0; box-shadow: var(--v2-focus-ring); } .v2-hint__content { display: none; position: absolute; z-index: 10; top: calc(100% + 6px); left: 0; width: min(320px, calc(100vw - 32px)); padding: 10px 12px; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); color: var(--v2-text-secondary); font: 400 13px/18px var(--v2-font); white-space: normal; box-shadow: 0 8px 24px rgba(15, 23, 42, .12); } .v2-hint--open .v2-hint__content { display: block; } @media (max-width: 760px) { .v2-root button.v2-hint__trigger { width: 28px; height: 28px; flex: 0 0 28px; } .v2-hint--open { display: flex; min-width: 0; max-width: 100%; align-items: flex-start; gap: 8px; } .v2-page-head__identity .v2-hint--open, .v2-thread__title-line .v2-hint--open { display: contents; } .v2-hint--open .v2-hint__content { position: static; width: auto; min-width: 0; padding: 0; border: 0; background: transparent; box-shadow: none; } .v2-page-head__identity .v2-hint__content, .v2-thread__title-line .v2-hint__content { width: 100%; flex-basis: 100%; order: 1; } } .v2-feature__body { flex: 1; min-height: 0; overflow-y: auto; padding: 28px 34px 42px; } .v2-feature__legacy { max-width: 1240px; margin: 0 auto; color: var(--v2-text-primary); } .v2-feature__legacy > .MuiContainer-root { max-width: none; padding-left: 0; padding-right: 0; } .v2-feature__legacy .MuiBox-root { color: var(--v2-text-primary); } .v2-feature__legacy .MuiTypography-root { color: inherit; } .v2-feature__legacy .MuiTypography-h1, .v2-feature__legacy .MuiTypography-h2, .v2-feature__legacy .MuiTypography-h3, .v2-feature__legacy .MuiTypography-h4, .v2-feature__legacy .MuiTypography-h5, .v2-feature__legacy .MuiTypography-h6 { color: var(--v2-text-primary); letter-spacing: -0.02em; } .v2-feature__legacy .MuiTypography-colorPrimary, .v2-feature__legacy .MuiSvgIcon-colorPrimary { color: var(--v2-accent-text); } .v2-feature__legacy .MuiTypography-colorTextSecondary, .v2-feature__legacy .MuiTypography-colorTextDisabled { color: var(--v2-text-secondary); } .v2-feature__legacy .MuiPaper-root { background: var(--v2-surface) !important; background-color: var(--v2-surface) !important; color: var(--v2-text-primary) !important; border: 1px solid var(--v2-border) !important; box-shadow: var(--v2-shadow-sm) !important; } .v2-feature__legacy .MuiPaper-elevation1, .v2-feature__legacy .MuiPaper-elevation2, .v2-feature__legacy .MuiPaper-elevation3, .v2-feature__legacy .MuiPaper-elevation4, .v2-feature__legacy .MuiPaper-elevation5, .v2-feature__legacy .MuiPaper-elevation6, .v2-feature__legacy .MuiPaper-elevation7, .v2-feature__legacy .MuiPaper-elevation8, .v2-feature__legacy .MuiPaper-elevation9, .v2-feature__legacy .MuiPaper-elevation10, .v2-feature__legacy .MuiPaper-elevation11, .v2-feature__legacy .MuiPaper-elevation12, .v2-feature__legacy .MuiPaper-elevation13, .v2-feature__legacy .MuiPaper-elevation14, .v2-feature__legacy .MuiPaper-elevation15, .v2-feature__legacy .MuiPaper-elevation16, .v2-feature__legacy .MuiPaper-elevation17, .v2-feature__legacy .MuiPaper-elevation18, .v2-feature__legacy .MuiPaper-elevation19, .v2-feature__legacy .MuiPaper-elevation20, .v2-feature__legacy .MuiPaper-elevation21, .v2-feature__legacy .MuiPaper-elevation22, .v2-feature__legacy .MuiPaper-elevation23, .v2-feature__legacy .MuiPaper-elevation24 { box-shadow: var(--v2-shadow-sm); } .v2-feature__legacy .MuiPaper-root, .v2-feature__legacy .MuiCard-root { border-radius: 12px; } .v2-feature__legacy .MuiCard-root { background: var(--v2-surface) !important; background-color: var(--v2-surface) !important; color: var(--v2-text-primary) !important; border: 1px solid var(--v2-border) !important; box-shadow: var(--v2-shadow-sm) !important; transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease !important; } .v2-feature__legacy .MuiCard-root:hover { border-color: var(--v2-border-strong) !important; box-shadow: var(--v2-shadow) !important; transform: translateY(-1px) !important; } .v2-feature__legacy .MuiCardContent-root, .v2-feature__legacy .MuiCardActions-root { background: transparent !important; color: var(--v2-text-primary) !important; } .v2-feature__legacy .MuiCardActions-root { border-top-color: var(--v2-border-soft) !important; } .v2-feature__legacy .MuiCard-root .MuiTypography-root { color: var(--v2-text-primary) !important; } .v2-feature__legacy .MuiCard-root .MuiTypography-colorTextSecondary, .v2-feature__legacy .MuiCard-root .MuiTypography-caption, .v2-feature__legacy .MuiCard-root .MuiTypography-body2 { color: var(--v2-text-secondary) !important; } .v2-feature__legacy .MuiCard-root [style*="color: rgb(226, 232, 240)"], .v2-feature__legacy .MuiCard-root [style*="color: #e2e8f0"], .v2-feature__legacy .MuiCard-root [style*="color: #cbd5f5"], .v2-feature__legacy .MuiCard-root [style*="color: #f8fafc"] { color: var(--v2-text-primary) !important; } .v2-feature__legacy .MuiCard-root [style*="color: rgb(148, 163, 184)"], .v2-feature__legacy .MuiCard-root [style*="color: #94a3b8"], .v2-feature__legacy .MuiCard-root [style*="color: #64748b"], .v2-feature__legacy .MuiCard-root [style*="color: #475569"] { color: var(--v2-text-secondary) !important; } .v2-feature__legacy .MuiButton-containedPrimary { background: var(--v2-accent); color: #ffffff; box-shadow: none; } .v2-feature__legacy .MuiButton-containedPrimary:hover { background: var(--v2-accent-strong); } .v2-feature__legacy .MuiButton-outlined { border-color: var(--v2-border); } .v2-feature__legacy .MuiButton-text, .v2-feature__legacy .MuiButton-outlined { color: var(--v2-accent-text); } .v2-feature__legacy .MuiIconButton-root { color: var(--v2-text-tertiary); } .v2-feature__legacy .MuiIconButton-root:hover { color: var(--v2-text-primary); background-color: var(--v2-surface-hover); } .v2-feature__legacy .MuiInputBase-root, .v2-feature__legacy .MuiSelect-select, .v2-feature__legacy .MuiAutocomplete-inputRoot { background-color: var(--v2-surface) !important; color: var(--v2-text-primary) !important; } .v2-feature__legacy .MuiOutlinedInput-notchedOutline { border-color: var(--v2-border); } .v2-feature__legacy .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline { border-color: var(--v2-border-strong); } .v2-feature__legacy .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline { border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-feature__legacy .MuiInputLabel-root, .v2-feature__legacy .MuiFormLabel-root { color: var(--v2-text-secondary); } /* Flatten MUI outlined form controls to the v2 look. The recolor above kept the MUI signature — a floated label sitting in a notched border. Here we finish the job: continuous border (kill the notch legend), v2 radius, and lift the label to a static v2-style label ABOVE the field. One block skins every legacy admin form (Global Integrations model policy, etc.) without a component rewrite. */ .v2-feature__legacy .MuiFormControl-root { margin-top: 20px; } .v2-feature__legacy .MuiOutlinedInput-root { border-radius: var(--v2-radius); } .v2-feature__legacy .MuiOutlinedInput-notchedOutline legend { max-width: 0.01px; } .v2-feature__legacy .MuiInputLabel-outlined { position: static; transform: none; margin-bottom: 6px; max-width: 100%; font-size: 12px; font-weight: 600; color: var(--v2-text-secondary); pointer-events: auto; overflow: visible; } .v2-feature__legacy .MuiInputBase-input, .v2-feature__legacy .MuiSelect-select { padding: 10px 12px; font-size: 14px; min-height: 20px; box-sizing: border-box; } .v2-feature__legacy .MuiDivider-root { border-color: var(--v2-border-soft); } .v2-feature__legacy .MuiTabs-root { border-bottom-color: var(--v2-border-soft); min-height: 42px; } .v2-feature__legacy .MuiTab-root { color: var(--v2-text-secondary); min-height: 42px; text-transform: none; font-weight: 700; } .v2-feature__legacy .MuiTab-root.Mui-selected { color: var(--v2-accent-text); } .v2-feature__legacy .MuiTabs-indicator { background-color: var(--v2-accent); } .v2-feature__legacy .MuiChip-root { border-radius: var(--v2-radius-pill); font-weight: 700; border-color: var(--v2-border) !important; } .v2-feature__legacy .MuiChip-filled:not(.MuiChip-colorSuccess):not(.MuiChip-colorWarning):not(.MuiChip-colorError):not(.MuiChip-colorInfo) { background-color: var(--v2-accent-soft) !important; color: var(--v2-accent-text) !important; } .v2-feature__legacy .MuiChip-outlined:not(.MuiChip-colorSuccess):not(.MuiChip-colorWarning):not(.MuiChip-colorError):not(.MuiChip-colorInfo) { background-color: var(--v2-surface) !important; color: var(--v2-text-secondary) !important; } .v2-feature__legacy .MuiChip-colorPrimary { background-color: var(--v2-accent-soft); color: var(--v2-accent-text); } .v2-feature__legacy .MuiAlert-root { border-radius: 12px; border: 1px solid transparent; } .v2-feature__legacy .MuiTableContainer-root { background: var(--v2-surface) !important; border: 1px solid var(--v2-border); border-radius: 12px; box-shadow: var(--v2-shadow-sm); } .v2-feature__legacy .MuiTableCell-root { border-bottom-color: var(--v2-border-soft); } .v2-feature__legacy .MuiTableHead-root .MuiTableCell-root { background-color: var(--v2-page-bg); color: var(--v2-text-secondary); font-weight: 800; } .v2-feature__legacy .MuiListItem-root { border-radius: 10px; } .v2-feature__legacy .MuiListItem-root:hover { background-color: var(--v2-surface-hover); } .v2-feature__legacy .MuiSkeleton-root { background-color: #f0eff8; } .v2-feature__legacy .MuiDialog-paper, .v2-feature__legacy .MuiPopover-paper, .v2-feature__legacy .MuiMenu-paper { background: var(--v2-surface) !important; color: var(--v2-text-primary) !important; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); box-shadow: var(--v2-shadow-lg); } .v2-feature__legacy .MuiBackdrop-root { background-color: rgba(17, 24, 39, 0.34); } .v2-feature__legacy .MuiAvatar-root { border: 2px solid var(--v2-surface); } /* Reset top padding for embedded dev tools so the v2 feature header is the only top-of-page chrome the user sees. The dev pages were authored to stand alone and add their own 24px+ top padding. */ .v2-feature__legacy .api-dev-root, .v2-feature__legacy .pod-context-dev-root { padding-top: 0 !important; } .v2-feature__legacy .api-dev-container, .v2-feature__legacy .pod-context-dev-container { padding-left: 0 !important; padding-right: 0 !important; } .v2-feature__legacy [style*="#1d9bf0"], .v2-feature__legacy [style*="#1976d2"], .v2-feature__legacy [style*="#6366f1"], .v2-feature__legacy [style*="rgb(29, 155, 240)"] { color: var(--v2-accent-text) !important; border-color: var(--v2-border-strong) !important; } .v2-feature__legacy [style*="background: linear-gradient"], .v2-feature__legacy [style*="background-color: rgba(15, 23, 42"], .v2-feature__legacy [style*="background-color: rgba(30, 41, 59"], .v2-feature__legacy [style*="background-color: #0f172a"], .v2-feature__legacy [style*="background-color: #0b1220"] { background: var(--v2-surface) !important; background-color: var(--v2-surface) !important; color: var(--v2-text-primary) !important; } .v2-feature__legacy [style*="background-color: rgb(245, 248, 250)"], .v2-feature__legacy [style*="background-color: #f5f8fa"], .v2-feature__legacy [style*="bgcolor: #f5f8fa"] { background-color: var(--v2-page-bg) !important; } .v2-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 48px; color: var(--v2-text-tertiary); } /* App boot has no content state to impersonate, so the minimal mark can own the moment. The dots use the exact typing keyframes; inline spinners retain their state-specific v2-spin affordance below. */ .v2-boot { flex: 1; display: grid; place-items: center; min-height: 0; background: var(--v2-page-bg); } .v2-boot__mark { width: 64px; height: 64px; color: var(--v2-accent); overflow: visible; } .v2-boot__mark-dot { transform-box: fill-box; transform-origin: center; animation: v2-typing-dot var(--motion-breath) infinite var(--motion-ease-breath); } .v2-boot__mark-dot:nth-of-type(2) { animation-delay: var(--motion-stagger); } .v2-boot__mark-dot:nth-of-type(3) { animation-delay: calc(var(--motion-stagger) + var(--motion-stagger)); } .v2-empty__title { font-size: 16px; font-weight: 700; color: var(--v2-text-primary); } .v2-empty__text { font-size: 13px; text-align: center; max-width: 360px; } .v2-spinner { width: 18px; height: 18px; border: 2px solid var(--v2-border); border-top-color: var(--v2-accent); border-radius: 50%; animation: v2-spin var(--motion-spin) var(--motion-ease-linear) infinite; display: inline-block; } @keyframes v2-spin { to { transform: rotate(360deg); } } /* ---------- Misc utilities ---------- */ .v2-divider { height: 1px; background: var(--v2-border); margin: 16px 0; } .v2-row { display: flex; align-items: center; gap: 8px; } .v2-row--between { justify-content: space-between; } .v2-mute { color: var(--v2-text-tertiary); } .v2-strong { font-weight: 700; color: var(--v2-text-primary); } @media (max-width: 1023px) { .v2-root { min-width: 0; } .v2-shell:not(.v2-shell--feature-wide) { grid-template-columns: var(--v2-rail-w) var(--v2-pods-w) minmax(0, 1fr); } /* Below the 3-pane width the inspector becomes a right DRAWER, not a casualty. Hiding the pane outright here made the avatar-stack button a no-op on phones: V2Layout mounts the pane on tap, CSS hid it, and the pod's members/files/artifacts were unreachable on mobile entirely (2026-08-26). The pane only exists in the DOM while open (V2Layout mounts it conditionally), so its presence IS the open state; the existing v2-inspector__close dismisses it. Shadow is allowed here: the design system reserves shadows for floating UI, which this now is. */ .v2-pane--inspector { position: fixed; top: 0; right: 0; bottom: 0; width: min(360px, calc(100vw - 48px)); z-index: 60; border-left: 1px solid var(--v2-border); box-shadow: -12px 0 32px rgba(17, 24, 39, 0.14); } } @media (max-width: 760px) { /* Phones: the card fills the screen; the drawers keep the shell tint. Both selectors, or the banner variant keeps the desktop height. */ .v2-pane--main, .v2-authenticated-shell .v2-pane--main { margin: 0; height: 100%; border: 0; border-radius: 0; } .v2-shell, .v2-shell--no-inspector, .v2-shell--feature { grid-template-columns: var(--v2-rail-w) minmax(0, 1fr); } .v2-chat__messages { padding-inline: 14px; } .v2-first-run__overlay { padding: 12px; } .v2-first-run { max-height: calc(100dvh - 24px); padding: 20px 16px; } .v2-first-run__heading-row { flex-direction: column; gap: 8px; } .v2-root button.v2-first-run__skip { align-self: flex-start; } /* Hide secondary panes — but NOT the pods sidebar OR the inspector, which are both drawers now (pods slide-over below; inspector fixed-right in the 1023px block above). This :not chain out-specifies the drawer rules (0-4-0 vs 0-1-0), so an omission here is an invisible mounted pane: the inspector was exactly that on phones until 2026-08-26 — the header avatar button mounted it, this rule erased it. */ .v2-pane:not(.v2-pane--rail):not(.v2-pane--main):not(.v2-pods-aside):not(.v2-pane--inspector) { display: none; } /* Pods sidebar → slide-over drawer. Off-canvas by default; .--open slides it in. Sits above the backdrop (z 60 vs 55). */ .v2-pods-aside { position: fixed; top: 0; left: 0; z-index: 60; width: min(86vw, 320px); height: 100vh; transform: translateX(-100%); transition: transform 0.22s ease; box-shadow: 2px 0 24px rgba(15, 17, 21, 0.18); border-right: 1px solid var(--v2-border-soft); } .v2-pods-aside--open { transform: translateX(0); } .v2-mobile-backdrop, .v2-inspector-backdrop { display: block; position: fixed; inset: 0; z-index: 55; border: none; margin: 0; padding: 0; background: rgba(15, 17, 21, 0.42); cursor: pointer; } /* Close (X) inside the drawer header. Title row becomes a flex row so the X sits at the far end. Drop the fixed 32px height so the 44px tap target fits. */ .v2-pods__title { display: flex; align-items: center; justify-content: space-between; height: auto; min-height: 44px; } .v2-pods__mobile-close { display: inline-grid; place-items: center; width: 44px; height: 44px; margin-right: -8px; color: var(--v2-text-secondary); border: none; background: transparent; border-radius: var(--v2-radius-sm); } .v2-pods__mobile-close:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-chat__header-row { flex-wrap: wrap; } .v2-chat__state-strip { grid-template-columns: 1fr; gap: 4px; } } /* Plan/Execute pill in pod chat header (replaces banner state-strip) */ .v2-chat__mode-toggle--header { height: 32px; margin-right: 4px; } .v2-chat__mode-toggle--header .v2-chat__mode-option { height: 24px; font-size: 11.5px; } .v2-chat__mode-toggle--execute { border-color: rgba(204, 92, 28, 0.4); background: rgba(252, 232, 220, 0.55); } .v2-chat__goal-meta { color: var(--v2-text-muted); font-weight: 500; } /* Reactions row under message body — fixture-rendered (read-only). Real reactions backend ships post-YC; this just renders [[reactions:...]] tokens populated by the demo seed. */ .v2-msg__reactions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; } .v2-msg__reaction { display: inline-flex; align-items: baseline; /* see button rule below -- ink vs box */ gap: 4px; height: 24px; padding: 0 8px; background: #f3f4f6; border: 1px solid #e5e7eb; border-radius: 999px; font-size: 12px; line-height: 1; color: #4b5563; font-variant-emoji: emoji; } .v2-msg__reaction:hover { background: var(--v2-surface-hover); } .v2-msg__reaction-emoji { font-size: 13px; /* Chip inner height (24px - 2x1px border). With baseline alignment on the * chip, this tall line box is the ONLY thing centering the glyph pair * vertically -- shrink it back to 1 and the pair top-hugs the chip. */ line-height: 22px; } .v2-msg__reaction-count { font-weight: 600; font-size: 11px; } /* Transient reason-a-reaction-failed line (bad emoji / not a member / rate * limited). Auto-clears after ~4s from the component. */ .v2-msg__reaction-error { font-size: 11px; color: var(--v2-danger, #c0392b); align-self: center; } /* Sprint B5 — interactive reaction chips + picker. Mine = an ink-bordered * selection; not-mine = subtle gray (existing rule above). Same * specificity workaround as other v2 buttons. */ .v2-root button.v2-msg__reaction { cursor: pointer; background: #f3f4f6; border: 1px solid #e5e7eb; color: #4b5563; height: 24px; padding: 0 8px; border-radius: 999px; display: inline-flex; /* Baseline, not center: box-centering aligns the spans' LAYOUT boxes, * but Apple Color Emoji ink extends below the baseline while digit ink * does not, so on desktop the count visibly rides high (reported * 2026-08-05, HQ screenshot; reproduced 3x-zoomed in Chromium). Digits * hanging on the emoji's baseline is how "\1F44D 2" renders in plain * inline text -- the reference that looks right on every platform. The * emoji span's 22px line-height (chip inner height, below) is what * vertically centers the shared line inside the fixed-height chip. */ align-items: baseline; gap: 4px; font-size: 12px; line-height: 1; } .v2-root button.v2-msg__reaction--mine { background: var(--v2-surface); border-color: var(--v2-ink); color: var(--v2-ink); } .v2-root button.v2-msg__reaction:hover:not(:disabled) { background: var(--v2-surface-hover); } .v2-root button.v2-msg__reaction:disabled { cursor: default; opacity: 0.8; } /* The standalone "+" trigger, its hover wrap, and the --bare collapsed row * were retired 2026-08-23: the reaction trigger lives in the * .v2-msg__actions hover cluster (placement ruling), and a reactions * row with no chips simply does not render — the phantom-band problem the * --bare machinery solved cannot occur at all now. The picker below is * shared by the cluster (which overrides its anchor to open downward). */ .v2-msg__reaction-picker { left: auto; right: 0; } .v2-msg__reaction-picker { position: absolute; bottom: calc(100% + 6px); left: 0; display: flex; gap: 2px; padding: 4px; background: var(--v2-surface, #fff); border: 1px solid var(--v2-border, #e5e7eb); border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); z-index: 10; } .v2-root button.v2-msg__reaction-picker-item { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; background: transparent; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; transition: background 0.1s ease; } .v2-root button.v2-msg__reaction-picker-item:hover { background: #f3f4f6; } .v2-root button.v2-msg__reaction-picker-item--mine { background: var(--v2-surface); border: 1px solid var(--v2-ink); } /* Sprint B3 — Bring-your-own MCP agent onboarding page. Lives at * /v2/agents/byo. Single-column form + result. Aligned with v2's * border-not-shadow aesthetic; accent-blue for interactive controls. */ /* The bar's space exists before it appears; its negative margin makes the sticky overlay occupy no additional flow space when it becomes visible. */ .v2-feature--byo { --v2-byo-offer-height: 96px; } .v2-feature--byo > .v2-feature__body { padding-bottom: 0; } .v2-byo__hosted-offer { position: sticky; bottom: 0; z-index: 5; box-sizing: border-box; min-height: var(--v2-byo-offer-height); margin-top: calc(-1 * var(--v2-byo-offer-height)); padding: 12px 24px; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; align-content: center; gap: 8px 16px; border-top: 1px solid var(--v2-border); background: var(--v2-surface); } .v2-byo__hosted-offer > p:first-child { margin: 0; color: var(--v2-text-muted); font: 400 13px/20px var(--v2-font); } .v2-root .v2-byo__hosted-offer button.v2-byo__hosted-offer-action { height: 40px; padding: 0 16px; align-self: center; } .v2-byo__hosted-offer .v2-byo__error { grid-column: 1 / -1; margin: 0; padding: 0; border: 0; } @media (max-width: 760px) { .v2-feature--byo { --v2-byo-offer-height: 128px; } .v2-byo__hosted-offer { grid-template-columns: minmax(0, 1fr); padding: 12px 16px; } .v2-root .v2-byo__hosted-offer button.v2-byo__hosted-offer-action { height: 44px; width: 100%; } } .v2-byo__form, .v2-byo__result { display: flex; flex-direction: column; gap: 18px; max-width: 720px; margin: 24px auto; } .v2-byo__result h2 { font-size: 20px; margin: 0; } /* The form's 18px gap is a field rhythm; the result's is a section rhythm, and it only shows once the snippet cards stop being cards (item 6). Declared separately so the form keeps 18 (ux-lead, TASK-169 render pass). */ .v2-byo__result { gap: 28px; } /* A

keeps its user-agent margin inside a flex column, and flex gaps do not collapse it — so the authored 28 was drawing as 42 (28 + the paragraph's 1em) and the h2's 4px rode on top of the next gap. The `>` is load-bearing: it zeroes the result's own flex children and leaves a paragraph nested inside a snippet its own rhythm. (ux-lead's TASK-169 render gate measured 28 at 1200 and 390 with exactly these declarations.) */ .v2-byo__result > p { margin: 0; } /* An agent's name in mono is a mark (Signal rule 1), so the name carries the accent — it is already named once in the sentence above it. */ .v2-byo__result h2 code { font-family: var(--v2-font-mono); font-weight: 500; color: var(--v2-accent-text); } .v2-byo__field { display: flex; flex-direction: column; gap: 6px; } .v2-byo__label { font-size: 13px; font-weight: 600; color: var(--v2-text-primary); } .v2-byo__input { padding: 10px 12px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface, #fff); font-size: 14px; color: var(--v2-text-primary); outline: none; transition: border-color 0.15s ease; } .v2-byo__input:focus { border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-byo__hint { font-size: 12px; color: var(--v2-text-tertiary); margin: 0; } /* Field guidance is available at the moment it is useful, not as a permanent second label. Errors keep the relevant hint visible until the person edits that field again. */ .v2-byo__field > .v2-byo__hint { display: none; } .v2-byo__field:focus-within > .v2-byo__hint, .v2-byo__field--error > .v2-byo__hint { display: block; } /* §3 error — a white card with a border, ink text, no icon. The red fill was the pre-Signal shape: it read as a state of the page rather than a message beside the field it belongs to. */ .v2-byo__error { padding: 12px 16px; border-radius: var(--v2-radius-lg); background: var(--v2-surface); border: 1px solid var(--v2-border); color: var(--v2-text-primary); font-size: 13px; line-height: 20px; } /* Optional memory import (retention plan Phase C) — lives inside the post-issue snippet card. */ .v2-byo__memory { display: flex; flex-direction: column; gap: 10px; /* The padding outlived the card it was inset in (item 6). */ padding: 0; } .v2-byo__memory > p { margin: 0; } /* `.v2-root textarea` (v2.css:211) inherits the family and outranks a lone class, so the 'SF Mono' stack never applied and this box rendered Plex Sans. The selector carries the element for the same reason. */ .v2-root textarea.v2-byo__memory-text { font-family: var(--v2-font-mono); font-size: 12px; resize: vertical; } /* The hint codes (MEMORY.md, CLAUDE.md) rendered in the UA monospace. */ .v2-byo__layout code { font-family: var(--v2-font-mono); font-weight: 500; } .v2-byo__memory-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; } /* §3 connected/live is never green, and it is never a ✓ either — the mark is the cobalt dot, which replaces the ✓ that used to open these lines (the dot and the ✓ together marked the same line twice). `memory-done` keeps its name because the memory line is a completed action, not a presence. */ .v2-byo__memory-done { padding: 0; margin: 0; color: var(--v2-text-primary); font-size: 13px; line-height: 20px; } .v2-byo__memory-done code { font-size: 12px; color: var(--v2-accent-text); } .v2-byo__live { display: flex; /* The dot marks presence on the FIRST line. Centred, it floats between the two lines once the sentence wraps at 390 (ux-lead's render gate). */ align-items: flex-start; gap: 8px; margin: 0; color: var(--v2-text-primary); font-size: 13px; line-height: 20px; } /* Agent presence, which is what §3's live dot means — so cobalt, and the same dot the preview rail shows one column over. (The Connectors dot is ink because it reports connection state, not presence.) */ .v2-byo__live::before { content: ''; flex: none; /* (20px line box − 7px dot) / 2, so the dot's centre lands on the first line's optical centre rather than at the top of its line box. */ margin-top: 6.5px; width: 7px; height: 7px; border-radius: 50%; background: var(--v2-accent); } /* BYO decision layout (2026-08-30). Form on the left, live agent preview on the right — the page shows the teammate being created, not a settings form. Tokens only; borders, not shadows. */ .v2-byo__layout { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: 44px; max-width: 1060px; margin: 0 auto; align-items: start; padding: 8px 24px calc(40px + var(--v2-byo-offer-height, 0px)); } /* Signal rule 4 — avatars are a 4px square frame. All four avatars on this route are in scope together (the persona context, the placed and hosted result cards, and the preview) because they show the same agent a click apart: a square preview that turns round after "Add to this computer" reads as two different things. The square is also what UNCLIPS the online dot — at 50% the base class's `overflow: hidden` cuts the 9px dot to a lens (ux-lead measured 13 device px at DPR 2, against 68 once square), so the cobalt rule below must land in the same scope, or the dot goes full green. (0,2,0) over `.v2-avatar`'s (0,1,0): this wins on specificity, with no dependency on document order. */ .v2-byo__layout .v2-avatar { border-radius: 4px; border: 0; box-shadow: none; } /* Signal §3 — connected/live is a solid cobalt dot, never green. Same (0,2,0) scope as the square; `.v2-avatar__online` carries its own 50% radius, so this rule must never declare one (the dot stays round). */ .v2-byo__layout .v2-avatar__online { background: var(--v2-accent); } .v2-byo__main { min-width: 0; } .v2-byo__preview { position: sticky; top: 24px; display: flex; flex-direction: column; gap: 10px; margin-top: 24px; } .v2-byo__preview-label { /* Signal rule 3 — meta is IBM Plex Mono 500 because it is data; the caps were a CSS transform over an en literal that is already sentence case. */ color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); letter-spacing: 0; } .v2-byo__preview-card { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 28px 20px 22px; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); text-align: center; } .v2-byo__preview-name { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; color: var(--v2-text-primary); margin-top: 6px; overflow-wrap: anywhere; } .v2-byo__preview-pod { font-size: 12px; color: var(--v2-text-tertiary); } /* The status line is Signal §3 in one row, and it has to agree with the avatar dot beside it: since item 7 makes that dot cobalt, a green success pill next to it reads as two different states of the same agent. So it is not a pill at all — it is the team card's mono 11/16 muted line, with the dot carrying the state (ux-lead's #1897 gate, measured at 1200/390). */ .v2-byo__preview-status { display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; padding: 0; border-radius: 0; background: none; font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-muted); } .v2-byo__preview-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--v2-text-muted); } /* §3 not yet — the dashed hollow dot the Connectors not-yet state uses (v2.css:9797). The text stays muted rather than placeholder: #98a2b3 at 11px is 2.6:1. `waiting` shares the ring: a token has been issued and the agent has not checked in, so the state is still "not yet" — but it is no longer "not created", and the rail said so while the page beside it said the install had succeeded (ux-lead, TASK-169). `waiting` is listed first on purpose: `ruleBody` matches the selector on the line that touches the brace, so the draft assertion keeps reading this block. */ .v2-byo__preview-status--waiting .v2-byo__preview-dot, .v2-byo__preview-status--draft .v2-byo__preview-dot { box-sizing: border-box; background: transparent; border: 1px dashed var(--v2-border-strong); } /* §3 working — the team card's working line (v2.css:12113–12122), same colour and same pulse, so "an agent is starting" reads identically in both places. */ .v2-byo__preview-status--starting { color: var(--v2-accent-text); } .v2-byo__preview-status--starting .v2-byo__preview-dot { background: var(--v2-accent); animation: v2-team-pulse 1.6s ease-in-out infinite; } @media (prefers-reduced-motion: reduce) { .v2-byo__preview-status--starting .v2-byo__preview-dot { animation: none; } } /* §3 connected / live — cobalt dot, muted text, no success colour and no fill. */ .v2-byo__preview-status--live { color: var(--v2-text-muted); } .v2-byo__preview-status--live .v2-byo__preview-dot { background: var(--v2-accent); } @media (max-width: 940px) { .v2-byo__layout { grid-template-columns: minmax(0, 1fr); } .v2-byo__preview { display: none; } } @media (max-width: 760px) { /* The shell already pads at this width, so the page's own padding landed on top of it and squeezed the command block to 274px at 390. */ .v2-byo__layout { padding-left: 0; padding-right: 0; } /* The Copy target is 30px tall by type; the ::after lifts it to a 44px touch target at phone widths only (v2-landing.css:261-273 precedent). */ .v2-byo__copy { position: relative; } .v2-byo__copy::after { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 44px; transform: translateY(-50%); } } .v2-byo__result-hero { display: flex; align-items: center; gap: 14px; } .v2-byo__result-hero h2 { margin: 0; } .v2-byo__stats { display: flex; gap: 12px; } .v2-byo__stat { flex: 1; display: flex; flex-direction: column; gap: 2px; padding: 12px 14px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); } /* Counts are data, and §3 sets data in mono. */ .v2-byo__stat-value { font: 500 18px/24px var(--v2-font-mono); letter-spacing: 0; color: var(--v2-text-primary); font-variant-numeric: tabular-nums; } .v2-byo__stat-label { font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-tertiary); } /* Persona context (2026-09-01): who was picked and why, carried from the catalog — or an honest "nobody yet" for the machine-first entry. */ .v2-byo__persona { display: flex; align-items: center; gap: 12px; padding: 12px 16px; margin-bottom: 16px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); } .v2-byo__persona-body { min-width: 0; flex: 1; } .v2-byo__persona-title { font-size: 14px; color: var(--v2-text-secondary); } .v2-byo__persona-title strong { color: var(--v2-text-primary); font-weight: 700; } .v2-byo__persona-line { font-size: 13px; color: var(--v2-text-tertiary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ADR-023 W2 — "Run it here" vs BYO choice cards. Borders, not shadows; the pressed card is marked by a 2px accent border, and the focus ring is the keyboard affordance only (Signal rules 1 and 4). */ .v2-byo__modes { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; } .v2-byo__mode-option { display: flex; min-width: 0; flex-direction: column; align-items: flex-start; gap: 3px; } .v2-root button.v2-byo__mode { display: flex; flex-direction: column; align-items: flex-start; align-self: stretch; gap: 5px; text-align: left; padding: 16px 18px 14px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface, var(--v2-bg)); color: var(--v2-text-primary); cursor: pointer; transition: border-color 0.08s ease, background 0.08s ease; } .v2-byo__mode-option > .v2-hint { margin-top: 0; } .v2-root button.v2-byo__mode:hover { background: var(--v2-surface-hover); } .v2-root button.v2-byo__mode:focus-visible { outline: 0; box-shadow: var(--v2-focus-ring); } .v2-root button.v2-byo__mode[aria-pressed="true"] { /* 2px border in place of the 1px one, with 1px less padding per side so the card holds its box: the base shorthand is `16px 18px 14px`, not uniform, so the `.v2-team-card--needsYou` precedent's single `15px` does not transfer (it would also lose 2px of width). No shadow — the focus ring belongs to `:focus-visible` (v2.css:383), which is why this rule must not declare one and the guard says so negatively. */ border: 2px solid var(--v2-accent); padding: 15px 17px 13px; } .v2-byo__mode-title { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; } .v2-root button.v2-byo__submit { /* Signal rule 2 — ink acts. A filled control inside the app is ink on white; cobalt fills a control in exactly one place, a decision card's primary. */ align-self: flex-start; padding: 10px 18px; border-radius: 4px; background: var(--v2-ink); color: var(--v2-on-ink); border: 1px solid var(--v2-ink); font-weight: 600; font-size: 14px; cursor: pointer; } .v2-root button.v2-byo__submit:hover:not(:disabled) { background: var(--v2-ink-hover); border-color: var(--v2-ink-hover); } .v2-root button.v2-byo__submit:disabled { opacity: 0.6; cursor: default; } /* The question above the choice cards. Nothing is preselected, so the page asks it in words rather than implying an answer with a pressed card. */ .v2-byo__modes-question { margin: 0; font-size: 13px; font-weight: 600; color: var(--v2-text-primary); } /* Signal §3 not yet: where the act will be, until a place to run it is chosen. A muted hint line, not a box: a dashed slot read as a dead button (TASK-647 item 1). */ .v2-byo__unchosen { align-self: flex-start; padding: 0; border: 0; color: var(--v2-text-muted); font-size: 13px; line-height: 20px; } .v2-root button.v2-byo__link { /* A text action beside or under a line of copy ("Change", "Other ways to connect"): the v2-team__link shape, so it reads as a link, not a button. */ padding: 0; border: 0; background: transparent; color: var(--v2-accent-text); font: 500 13px/20px var(--v2-font); cursor: pointer; align-self: flex-start; } .v2-root .v2-byo__needs { /* What a stranger needs before the paste (QA BYO walk 1): one line above the command, in body ink, so it is read before the Copy button is. */ margin: 0; font: 400 13px/20px var(--v2-font); color: var(--v2-text-primary); } .v2-root .v2-byo__os { /* Which machine the commands are for: Windows gets WSL for the listener and PowerShell lines for MCP. The chosen one reads as ink, not a link. */ margin: 0; font: 400 13px/20px var(--v2-font); color: var(--v2-text-secondary); } .v2-root button.v2-byo__link[aria-pressed="true"] { color: var(--v2-text-primary); font-weight: 600; text-decoration: none; } .v2-root .v2-byo__more { /* "Other ways to connect": the real alternatives, folded so the page shows one command, not five equal choices. */ display: flex; flex-direction: column; gap: 12px; } .v2-root .v2-byo__more > summary { cursor: pointer; color: var(--v2-accent-text); font: 500 13px/20px var(--v2-font); } .v2-root a.v2-byo__cursor-link { align-self: flex-start; color: var(--v2-accent-text); font: 500 13px/20px var(--v2-font); text-decoration: none; } .v2-root a.v2-byo__cursor-link:hover { text-decoration: underline; } .v2-root button.v2-byo__secondary { align-self: flex-start; padding: 10px 18px; border-radius: var(--v2-radius); background: transparent; color: var(--v2-text-secondary); border: 1px solid var(--v2-border); font-weight: 600; font-size: 14px; cursor: pointer; } .v2-root button.v2-byo__secondary:hover { background: var(--v2-surface-hover); } /* §4 command blocks. A snippet is a flat section of the page, not a card, and Copy sits on the ink ground beside the command it copies rather than in the head — the head is a label. */ .v2-byo__snippet { display: flex; flex-direction: column; gap: 8px; padding: 0; border: 0; border-radius: 0; overflow: visible; background: none; } .v2-byo__snippet-head { display: block; padding: 0; border: 0; background: none; font: 600 14px/20px var(--v2-font); color: var(--v2-text-primary); } .v2-byo__snippet > p { margin: 0; } /* minmax(0, 1fr) is the fix for the clipped command: a fr column may not shrink below its content's min-content width, and a nowrap command's is its full width (the daemon command measured 771px in a 575px box). */ .v2-byo__command { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: start; padding: 12px; border-radius: var(--v2-radius-sm); background: var(--v2-ink); } .v2-root button.v2-byo__copy { min-height: 30px; padding: 5px 9px; border: 1px solid var(--v2-accent); border-radius: var(--v2-radius-sm); background: var(--v2-accent); color: var(--v2-on-ink); font: 600 12px/16px var(--v2-font); cursor: pointer; } .v2-root button.v2-byo__copy:hover { background: var(--v2-accent-strong); border-color: var(--v2-accent-strong); color: var(--v2-on-ink); } .v2-byo__pre { margin: 0; /* 5px centres the first line on the 30px Copy beside it. */ padding: 5px 0 0; font: 500 14px/20px var(--v2-font-mono); color: var(--v2-on-ink); white-space: pre-wrap; /* Wrap at spaces, and inside a word only when one word cannot fit (the key, a URL). break-all split the Windows PowerShell line as "common / ly-mcp" at 1440 (browser check on #2289), which misleads anyone typing it. */ overflow-wrap: anywhere; } /* ADR-026 D1: one-paste computer setup, shown only while no machine exists. */ .v2-byo__add-computer { display: flex; flex-direction: column; gap: 10px; padding: 18px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-bg-subtle); } .v2-byo__add-computer > p { margin: 0; } .v2-byo__add-computer-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: start; padding: 12px; border-radius: var(--v2-radius-sm); background: var(--v2-ink); } .v2-byo__add-computer-row code { padding: 5px 0 0; border: 0; border-radius: 0; background: none; font: 500 14px/20px var(--v2-font-mono); color: var(--v2-on-ink); white-space: normal; overflow-wrap: anywhere; overflow: visible; } .v2-byo__cta-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 8px; } .v2-byo__footnote { font-size: 13px; color: var(--v2-text-tertiary); } .v2-byo__footnote code { font-family: var(--v2-font-mono); font-weight: 500; font-size: 12px; padding: 2px 6px; background: var(--v2-bg-subtle); border-radius: 4px; } /* ---------- Connect — CLI, MCP, and agent runtime entry points ---------- */ .v2-connect { display: flex; flex-direction: column; gap: 16px; max-width: 960px; margin: 0 auto; } .v2-connect__lane { padding: 20px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); } .v2-connect__lane-heading { display: flex; align-items: flex-start; gap: 12px; } .v2-connect__number { flex: 0 0 auto; padding-top: 3px; color: var(--v2-accent-text); font-family: "SF Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; font-weight: 700; } .v2-connect__lane h2 { margin: 0; color: var(--v2-text-primary); font-size: 16px; font-weight: 700; letter-spacing: -0.01em; } .v2-connect__lane-heading p, .v2-connect__note { margin: 5px 0 0; color: var(--v2-text-secondary); font-size: 13px; line-height: 1.5; } .v2-connect__code-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 18px; } .v2-connect__code-card { overflow: hidden; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); background: var(--v2-bg-subtle); } .v2-connect__code-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 10px; border-bottom: 1px solid var(--v2-border-soft); color: var(--v2-text-secondary); font-size: 12px; font-weight: 650; } .v2-connect__code-card pre { min-height: 92px; margin: 0; padding: 12px; overflow-x: auto; color: var(--v2-text-primary); font-family: "SF Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; } .v2-root button.v2-connect__copy, .v2-root .v2-connect__secondary, .v2-root .v2-connect__cta { display: inline-flex; align-items: center; justify-content: center; min-height: 34px; padding: 7px 11px; border-radius: var(--v2-radius-sm); font-size: 13px; font-weight: 650; text-decoration: none; cursor: pointer; } .v2-root button.v2-connect__copy, .v2-root .v2-connect__secondary { border: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-secondary); } .v2-root button.v2-connect__copy:hover, .v2-root .v2-connect__secondary:hover { border-color: var(--v2-border-strong); background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root .v2-connect__cta { border: 1px solid var(--v2-ink); background: var(--v2-ink); color: var(--v2-on-ink); } .v2-root .v2-connect__cta:hover:not(:disabled) { border-color: var(--v2-ink-hover); background: var(--v2-ink-hover); } .v2-root .v2-connect__cta:disabled { cursor: default; opacity: 0.6; } .v2-connect__note { margin-top: 12px; } .v2-connect__note code { font-family: "SF Mono", ui-monospace, SFMono-Regular, Menlo, monospace; } .v2-root a.v2-connect__link { display: inline-block; margin-top: 12px; color: var(--v2-accent-text); font-size: 13px; font-weight: 650; text-decoration: none; } .v2-root a.v2-connect__link:hover { text-decoration: underline; } .v2-connect__cursor { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin-top: 12px; color: var(--v2-text-tertiary); font: 400 13px/20px var(--v2-font); } .v2-root .v2-connect__cursor .v2-connect__link { margin-top: 0; } .v2-connect__rule { margin-top: 12px; } .v2-connect__rule .v2-connect__code-head span { min-width: 0; } .v2-connect__rule .v2-connect__code-head code { font-family: "SF Mono", ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere; } .v2-connect__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; } @media (max-width: 760px) { .v2-connect__lane { padding: 16px; } .v2-connect__code-grid { grid-template-columns: 1fr; } } /* ---------- Admin · Users (waitlist + invitation codes) ---------- */ .v2-admin-users { display: flex; flex-direction: column; gap: 32px; max-width: 1100px; } .v2-admin-users__section { display: flex; flex-direction: column; gap: 14px; } .v2-admin-users__section-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; } .v2-admin-users__section-title { font-size: 17px; font-weight: 700; color: var(--v2-text-primary); margin: 0; } .v2-admin-users__section-sub { font-size: 13px; color: var(--v2-text-tertiary); margin: 2px 0 0 0; } .v2-admin-users__controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } .v2-admin-users__input { flex: 1 1 280px; min-width: 220px; padding: 9px 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); font-size: 14px; color: var(--v2-text-primary); outline: none; transition: border-color 0.15s ease, box-shadow 0.15s ease; } .v2-admin-users__input:focus { border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-admin-users__tabs { display: inline-flex; gap: 4px; padding: 3px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-pill); background: var(--v2-surface); } .v2-root button.v2-admin-users__tab { padding: 6px 14px; border: none; border-radius: var(--v2-radius-pill); background: transparent; color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; cursor: pointer; transition: background 0.12s ease, color 0.12s ease; } .v2-root button.v2-admin-users__tab:hover { color: var(--v2-text-primary); } .v2-root button.v2-admin-users__tab--active { background: var(--v2-accent-soft); color: var(--v2-accent-text); } .v2-admin-users__table-wrap { border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); overflow-x: auto; background: var(--v2-surface); } .v2-admin-users__table { width: 100%; border-collapse: collapse; font-size: 13px; } .v2-admin-users__table th { text-align: left; padding: 10px 14px; font-size: 12px; font-weight: 700; color: var(--v2-text-tertiary); text-transform: uppercase; letter-spacing: 0.03em; background: var(--v2-bg-subtle); border-bottom: 1px solid var(--v2-border); white-space: nowrap; } .v2-admin-users__table td { padding: 12px 14px; border-bottom: 1px solid var(--v2-border-soft); color: var(--v2-text-secondary); vertical-align: top; } .v2-admin-users__table tbody tr:last-child td { border-bottom: none; } .v2-admin-users__cell-strong { color: var(--v2-text-primary); font-weight: 600; } .v2-admin-users__cell-muted { color: var(--v2-text-tertiary); white-space: nowrap; } .v2-admin-users__cell-wrap { max-width: 260px; } .v2-admin-users__note { display: block; font-size: 12px; color: var(--v2-text-tertiary); margin-top: 2px; } .v2-admin-users__actions { white-space: nowrap; text-align: right; } .v2-admin-users__badge { display: inline-block; padding: 2px 10px; border-radius: var(--v2-radius-pill); font-size: 12px; font-weight: 700; text-transform: capitalize; } .v2-admin-users__badge--ok { background: var(--v2-success-soft); color: #0f7a52; } .v2-admin-users__badge--warn { background: var(--v2-warning-soft); color: #9a5a12; } .v2-admin-users__badge--muted { background: var(--v2-surface-hover); color: var(--v2-text-tertiary); } .v2-root button.v2-admin-users__btn { padding: 8px 14px; border-radius: var(--v2-radius-sm); font-size: 13px; font-weight: 600; cursor: pointer; border: 1px solid transparent; transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease; } .v2-root button.v2-admin-users__btn:disabled { opacity: 0.6; cursor: default; } .v2-root button.v2-admin-users__btn--primary { background: var(--v2-accent-fill); border-color: var(--v2-accent); color: var(--v2-on-accent); } .v2-root button.v2-admin-users__btn--primary:hover:not(:disabled) { background: var(--v2-accent-strong); border-color: var(--v2-accent-strong); } .v2-root button.v2-admin-users__btn--ghost { background: var(--v2-surface); border-color: var(--v2-border); color: var(--v2-text-secondary); } .v2-root button.v2-admin-users__btn--ghost:hover:not(:disabled) { background: var(--v2-surface-hover); border-color: var(--v2-border-strong); color: var(--v2-text-primary); } .v2-root button.v2-admin-users__btn--danger { background: var(--v2-surface); border-color: var(--v2-border); color: var(--v2-danger); } .v2-root button.v2-admin-users__btn--danger:hover:not(:disabled) { background: #fee2e2; border-color: #fca5a5; color: #991b1b; } .v2-admin-users__loading { display: flex; align-items: center; gap: 10px; padding: 24px 4px; color: var(--v2-text-tertiary); font-size: 14px; } .v2-admin-users__error { padding: 10px 12px; border-radius: var(--v2-radius-sm); background: #fee2e2; border: 1px solid #fca5a5; color: #991b1b; font-size: 13px; } .v2-admin-users__notice-row td { padding-top: 0; } .v2-admin-users__notice { padding: 8px 12px; border-radius: var(--v2-radius-sm); background: var(--v2-warning-soft); border: 1px solid #f0c98a; color: #9a5a12; font-size: 12px; } .v2-admin-users__newcode { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 14px 16px; border: 1px solid var(--v2-accent-soft); border-radius: var(--v2-radius-lg); background: var(--v2-accent-soft); } .v2-admin-users__newcode-label { font-size: 13px; font-weight: 600; color: var(--v2-accent-text); flex: 1 1 100%; } .v2-admin-users__newcode-value { font-family: var(--v2-font-mono); font-size: 15px; font-weight: 700; letter-spacing: 0.04em; color: var(--v2-text-primary); padding: 6px 12px; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); } .v2-admin-users__code { font-family: var(--v2-font-mono); font-size: 13px; color: var(--v2-text-primary); } .v2-root button.v2-admin-users__inline-copy { margin-left: 8px; padding: 2px 8px; border-radius: var(--v2-radius-sm); border: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-secondary); font-size: 11px; font-weight: 600; cursor: pointer; } .v2-root button.v2-admin-users__inline-copy:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } /* Registered-users moderation (V2AdminUsers users section). */ .v2-admin-users__search { height: 34px; padding: 0 12px; min-width: 240px; font-size: 13.5px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); } .v2-admin-users__badge--banned { background: #fdecea; color: #c0392b; } .v2-root button.v2-admin-users__btn--danger { color: #c0392b; border-color: #e5b4ae; } .v2-root button.v2-admin-users__btn--danger:hover:not(:disabled) { background: #fdecea; } .v2-admin-users__row-actions { display: flex; gap: 8px; } /* Narrow screens: the team-card actions (Profile + Talk to) would otherwise squeeze the body column to zero width — the agent NAME disappeared at 390px (mobile smoke 2026-07-05, worsened by the added Profile button). Wrap the actions onto their own full-width row instead of competing with the name. */ /* Reply/Thread inline head buttons retired 2026-08-23 (taste ruling): the actions live in the .v2-msg__actions hover cluster now — one pill, all row variants, zero layout shift. See the cluster block near .v2-msg. Touch layouts keep ≥44px targets via the media block below. */ @media (hover: none), (pointer: coarse) { /* iOS Safari auto-zooms on focusing any input under 16px and does not zoom back on blur — the shell's inputs ranged 12–15px, so every tap on the composer or a search field left the page stuck zoomed ( 2026-08-26). 16px on touch devices removes the trigger entirely; this is the root fix, NOT the viewport maximum-scale hack, which blocks pinch-zoom on Android and is an accessibility regression. !important is deliberate: it must beat every per-component size including the legacy 15px !important, and a device-scoped accessibility floor is the rare case that earns it. */ .v2-root input, .v2-root textarea, .v2-root select { font-size: 16px !important; } /* No hover on touch — but always-on clusters over every message are chrome over content (2026-08-23). A tap on the message toggles .v2-msg--reveal (V2MessageRow.onBubbleTap, gated to hoverless devices); only then does the cluster appear, at the 44px floor (craft baseline rule 9). Absolute positioning preserved — a static third child would break the avatar|body grid. */ .v2-msg--reveal .v2-msg__actions, .v2-msg__actions:focus-within { opacity: 1; pointer-events: auto; } .v2-root button.v2-msg__action { width: 44px; height: 44px; } } .v2-msg__quote { display: flex; gap: 6px; margin: 2px 0 4px; padding: 4px 10px; border-left: 3px solid var(--v2-border); font-size: 12.5px; color: var(--v2-text-secondary); overflow: hidden; } .v2-msg__quote-author { font-weight: 600; flex-shrink: 0; } .v2-msg__quote-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-chat__reply-chip { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; padding: 6px 12px; font-size: 12.5px; color: var(--v2-text-secondary); background: var(--v2-surface-hover); border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); } .v2-chat__reply-chip-label { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .v2-root button.v2-chat__reply-chip-cancel { flex-shrink: 0; border: none; background: transparent; font-size: 16px; line-height: 1; color: var(--v2-text-secondary); cursor: pointer; } /* ============ Admin analytics (GH#662) ============ */ .v2-admin-analytics { display: flex; flex-direction: column; gap: 24px; max-width: 1100px; } .v2-admin-analytics__head-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; } .v2-root a.v2-admin-analytics__crosslink { font-size: 13px; font-weight: 600; color: var(--v2-accent-text); } .v2-admin-analytics__cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; } .v2-admin-analytics__card { padding: 14px 16px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); } .v2-admin-analytics__card-value { font-size: 26px; font-weight: 700; color: var(--v2-text-primary); font-variant-numeric: tabular-nums; } .v2-admin-analytics__card-label { font-size: 12px; color: var(--v2-text-tertiary); margin-top: 2px; } .v2-admin-analytics__charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; } .v2-admin-analytics__chart-card { padding: 14px 16px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); min-width: 0; } .v2-admin-analytics__chart-title { font-size: 12px; font-weight: 700; color: var(--v2-text-tertiary); text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 8px; } .v2-admin-analytics__chart { display: block; width: 100%; height: 120px; } .v2-admin-analytics__bar { fill: var(--v2-accent); opacity: 0.85; } .v2-admin-analytics__row--empty td { color: var(--v2-text-tertiary); } /* ---------- Billing panel (/v2/settings) ---------- */ /* `.v2-root button.` prefix throughout keeps each billing action's visual * treatment explicit. The global button reset is a low-specificity default, * so ordinary component rules can now override it without a specificity hack. */ .v2-billing { border: 1px solid var(--v2-border); border-radius: var(--v2-radius-md); padding: 16px; margin-bottom: 16px; background: var(--v2-bg); } .v2-billing__head { display: flex; align-items: center; gap: 10px; } .v2-billing__title { margin: 0; font-size: 15px; font-weight: 700; color: var(--v2-text-primary); } .v2-billing__badge { font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; background: var(--v2-surface); border: 1px solid var(--v2-border); color: var(--v2-text-secondary); } .v2-billing__badge--pro { background: var(--v2-accent-soft); border-color: var(--v2-accent); color: var(--v2-accent-text); } .v2-billing__note { margin: 8px 0 0; font-size: 13px; line-height: 1.5; color: var(--v2-text-secondary); } .v2-billing__warn { margin: 8px 0 0; font-size: 12px; color: var(--v2-text-secondary); } .v2-billing__error { margin: 8px 0 0; font-size: 12px; color: var(--v2-danger, #c0392b); } .v2-billing__actions { margin-top: 14px; display: flex; gap: 8px; } .v2-root button.v2-billing__btn { height: 34px; padding: 0 14px; border-radius: var(--v2-radius-sm); border: 1px solid var(--v2-border); background: var(--v2-bg); color: var(--v2-text-primary); font-size: 13px; font-weight: 600; cursor: pointer; transition: background 80ms ease, border-color 80ms ease; } .v2-root button.v2-billing__btn:hover:not(:disabled) { border-color: var(--v2-border-strong); } .v2-root button.v2-billing__btn--primary { background: var(--v2-ink); border-color: var(--v2-ink); color: var(--v2-on-ink); } .v2-root button.v2-billing__btn--primary:hover:not(:disabled) { background: var(--v2-ink-hover); border-color: var(--v2-ink-hover); } .v2-root button.v2-billing__btn:disabled { opacity: 0.7; cursor: default; } /* ---------- Settings (/v2/settings) ---------- */ .v2-settings { width: min(100%, 1040px); margin: 0 auto; color: var(--v2-text-primary); } .v2-settings__layout { display: grid; grid-template-columns: 200px minmax(0, 1fr); grid-template-rows: auto 1fr; gap: 0 40px; padding-top: 40px; } .v2-settings__title { grid-column: 1; grid-row: 1; margin: 0; color: var(--v2-text-primary); font-family: var(--v2-font-display); font-size: 28px; font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; } .v2-settings__nav { grid-column: 1; grid-row: 2; position: sticky; top: 24px; align-self: start; } .v2-settings__nav-list { display: grid; gap: 2px; margin-top: 24px; } .v2-root a.v2-settings__nav-link { display: flex; align-items: center; min-height: 38px; padding: 0 8px; border-radius: var(--v2-radius-sm); color: var(--v2-text-secondary); font-family: var(--v2-font); font-size: 14px; font-weight: 400; line-height: 20px; text-decoration: none; } .v2-root a.v2-settings__nav-link:hover { color: var(--v2-text-primary); } .v2-root a.v2-settings__nav-link--active { color: var(--v2-text-primary); background: var(--v2-bg-subtle); font-weight: 600; } .v2-root a.v2-settings__nav-link:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 2px; } .v2-settings__nav-note { margin: 24px 0 0; padding-top: 16px; border-top: 1px solid var(--v2-border-soft); color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 12px; line-height: 16px; } .v2-settings__section { padding: 28px 0; border-bottom: 1px solid var(--v2-border-soft); scroll-margin-top: 24px; } .v2-settings__label { margin: 0 0 16px; color: var(--v2-text-primary); font-family: var(--v2-font-display); font-size: 20px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; } .v2-settings__section-body { min-width: 0; } .v2-settings__link-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: baseline; gap: 12px; padding: 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); color: var(--v2-text-primary); text-decoration: none; } .v2-settings__link-row:hover { background: var(--v2-surface-hover); } .v2-settings__link-row:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 2px; } .v2-settings__link-row-label { font: 600 13px/18px var(--v2-font); } .v2-settings__link-row-detail { color: var(--v2-text-muted); font-size: 12px; } .v2-settings__link-row-arrow { color: var(--v2-accent-text); font-size: 18px; line-height: 18px; } .v2-settings__developer-disclosure { margin-top: 20px; border-top: 1px solid var(--v2-border-soft); padding-top: 16px; } .v2-settings__developer-disclosure > summary { color: var(--v2-text-primary); cursor: pointer; font: 600 13px/18px var(--v2-font); } .v2-settings__developer-disclosure[open] > summary { margin-bottom: 16px; } .v2-settings__content { grid-column: 2; grid-row: 1 / span 2; } .v2-settings__account-row { display: flex; align-items: center; gap: 12px; min-height: 44px; } .v2-settings__avatar { width: 64px; height: 64px; flex: 0 0 64px; border: 0; border-radius: var(--v2-radius-sm); font-size: 12px; } .v2-settings__avatar img { width: 64px; height: 64px; border-radius: var(--v2-radius-sm); } .v2-settings__account-copy { min-width: 0; } .v2-settings__account { min-width: 0; } .v2-settings__avatar-file-input { display: none; } .v2-settings__avatar-actions { display: flex; gap: 8px; margin-top: 12px; } .v2-settings__avatar-description { margin: 12px 0 0; color: var(--v2-text-secondary); font-size: var(--v2-fs-body); line-height: var(--v2-lh-body); } .v2-settings__avatar-overlay { z-index: 1000; background: rgba(16, 24, 40, 0.55); } .v2-settings__avatar-dialog { width: min(560px, 100%); } .v2-settings__avatar-crop-stage { position: relative; width: 100%; aspect-ratio: 392 / 260; overflow: hidden; border-radius: var(--v2-radius-sm); background: var(--v2-surface-tint); } .v2-settings__avatar-crop { display: block; position: relative; z-index: 0; width: 100%; height: 100%; border: 0; background: transparent; cursor: grab; touch-action: none; } .v2-settings__avatar-crop:active { cursor: grabbing; } .v2-settings__avatar-crop-dim { position: absolute; z-index: 1; inset: 0; pointer-events: none; } .v2-settings__avatar-crop-dim span { position: absolute; display: block; background: rgba(16, 24, 40, 0.55); } .v2-settings__avatar-crop-dim-top { inset: 0 0 auto; height: 21%; } .v2-settings__avatar-crop-dim-right { inset: 21% 0 21% auto; width: 30.765%; } .v2-settings__avatar-crop-dim-bottom { inset: auto 0 0; height: 21%; } .v2-settings__avatar-crop-dim-left { inset: 21% auto 21% 0; width: 30.765%; } .v2-settings__avatar-crop-frame { position: absolute; z-index: 2; top: 50%; left: 50%; width: 38.47%; aspect-ratio: 1; transform: translate(-50%, -50%); border: 1px solid var(--v2-surface); pointer-events: none; } .v2-settings__avatar-crop-loading { margin: -8px 0 0; color: var(--v2-text-tertiary); font-size: var(--v2-fs-meta); } .v2-settings__avatar-zoom { display: flex; align-items: center; gap: 12px; width: 100%; color: var(--v2-text-secondary); font-family: var(--v2-font-mono); font-size: var(--v2-fs-label); line-height: var(--v2-lh-label); text-transform: uppercase; } .v2-root .v2-settings__avatar-zoom input[type="range"] { flex: 1; min-width: 0; height: 16px; margin: 0; padding: 0; appearance: none; -webkit-appearance: none; border: 0; background: transparent; cursor: pointer; } .v2-root .v2-settings__avatar-zoom input[type="range"]::-webkit-slider-runnable-track { height: 2px; background: linear-gradient( 90deg, var(--v2-ink) 0 var(--avatar-zoom-progress), var(--v2-border-soft) var(--avatar-zoom-progress) 100% ); } .v2-root .v2-settings__avatar-zoom input[type="range"]::-moz-range-track { height: 2px; border: 0; background: var(--v2-border-soft); } .v2-root .v2-settings__avatar-zoom input[type="range"]::-moz-range-progress { height: 2px; background: var(--v2-ink); } .v2-root .v2-settings__avatar-zoom input[type="range"]::-webkit-slider-thumb { width: 16px; height: 16px; margin-top: -7px; appearance: none; -webkit-appearance: none; border: 0; border-radius: var(--v2-radius-sm); background: var(--v2-ink); } .v2-root .v2-settings__avatar-zoom input[type="range"]::-moz-range-thumb { width: 16px; height: 16px; border: 0; border-radius: var(--v2-radius-sm); background: var(--v2-ink); } .v2-root .v2-settings__avatar-zoom input[type="range"]:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 4px; } .v2-settings__avatar-footer { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; width: 100%; } .v2-settings__avatar-previews { display: flex; align-items: flex-end; justify-content: flex-start; gap: 12px; } .v2-settings__avatar-preview { display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--v2-text-tertiary); font-size: 12px; line-height: var(--v2-lh-label); } .v2-settings__avatar-preview-image { display: block; max-width: 64px; max-height: 64px; object-fit: cover; border-radius: var(--v2-radius-sm); } .v2-settings__avatar-preview-image--64 { width: 64px; height: 64px; } .v2-settings__avatar-preview-image--32 { width: 32px; height: 32px; } .v2-settings__avatar-preview-image--22 { width: 22px; height: 22px; } .v2-settings__avatar-dialog-actions { display: flex; justify-content: flex-end; gap: 12px; } .v2-root .v2-settings__avatar-dialog-actions button { min-width: 112px; } /* Neutralize App.css's bare auth-form shell: Settings owns this form's * surface and spacing, so it must stay flat inside its section. */ .v2-settings form.v2-settings__account { max-width: none; margin: 0; padding: 0; border-radius: 0; background: transparent; box-shadow: none; } .v2-settings__account-name { overflow: hidden; color: var(--v2-text-primary); font-family: var(--v2-font-display); font-size: 18px; font-weight: 700; letter-spacing: -0.02em; text-overflow: ellipsis; white-space: nowrap; } .v2-settings__account-type, .v2-settings__meta { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: var(--v2-fs-meta); line-height: var(--v2-lh-meta); } /* Administration (admin-only): two bordered link rows, ink label + muted detail. */ .v2-settings__admin-links { display: flex; flex-direction: column; gap: 8px; } .v2-settings__admin-link { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 10px 12px; border: 1px solid var(--v2-border); border-radius: 4px; color: var(--v2-text-primary); text-decoration: none; } .v2-settings__admin-link:hover { background: var(--v2-surface-hover); } .v2-settings__admin-link-label { font: 600 13px/18px var(--v2-font); } .v2-settings__admin-link-detail { font-size: 12px; color: var(--v2-text-muted); text-align: right; } .v2-settings__account-type { margin-left: auto; text-transform: lowercase; } .v2-settings__account-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 16px; } .v2-settings__account-fields label, .v2-settings__account-email { display: grid; gap: 6px; min-width: 0; color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: var(--v2-fs-meta); line-height: var(--v2-lh-meta); } .v2-settings__account-fields > label { align-content: start; } .v2-settings__account-fields > .v2-settings__account-email { grid-column: 1 / -1; } .v2-settings__account-fields input { box-sizing: border-box; width: 100%; min-height: 36px; padding: 7px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); font: 400 14px/20px var(--v2-font); } .v2-settings__account-fields input:focus { outline: none; border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-settings__account-fields input[readonly] { color: var(--v2-text-secondary); cursor: default; } .v2-settings__email-control { display: flex; align-items: center; gap: 8px; } .v2-settings__email-control input { min-width: 0; } .v2-settings__email-control .v2-settings__secondary { align-self: stretch; flex: 0 0 auto; white-space: nowrap; } .v2-settings__username-control { display: flex; align-items: center; gap: 8px; } .v2-settings__username-control input { min-width: 0; } .v2-settings__username-control .v2-settings__secondary { align-self: stretch; flex: 0 0 auto; white-space: nowrap; } .v2-settings__field-help { color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-settings__section .v2-billing, .v2-settings__section .v2-devices { margin: 0; padding: 0; border: 0; border-radius: 0; background: transparent; } .v2-settings__section .v2-billing__badge { border-radius: var(--v2-radius-sm); background: var(--v2-surface); border-color: var(--v2-border); color: var(--v2-text-primary); font-family: var(--v2-font-mono); font-size: 12px; font-weight: 500; letter-spacing: 0; line-height: 16px; text-transform: none; } .v2-settings__section .v2-billing__badge--pro { background: var(--v2-accent); border-color: var(--v2-accent); color: var(--v2-on-ink); } .v2-settings__section .v2-devices__item { border-radius: var(--v2-radius-sm); } .v2-settings__section .v2-devices__empty { padding: 0; background: transparent; } .v2-settings__token-value { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 8px; align-items: center; } .v2-settings__token-value code { overflow: hidden; min-height: 40px; padding: 10px 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); color: var(--v2-text-primary); font-family: var(--v2-font-mono); font-size: 12px; line-height: 18px; text-overflow: ellipsis; white-space: nowrap; } .v2-settings__token-meta { margin: 8px 0 0; color: var(--v2-text-tertiary); font-family: var(--v2-font); font-size: var(--v2-fs-body); line-height: var(--v2-lh-body); } .v2-settings__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; } .v2-root button.v2-settings__primary, .v2-root button.v2-settings__secondary { min-height: 36px; padding: 0 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-bg); color: var(--v2-text-primary); font: 600 13px/20px var(--v2-font); cursor: pointer; } .v2-root button.v2-settings__primary { border-color: var(--v2-ink); background: var(--v2-ink); color: var(--v2-on-ink); } .v2-root button.v2-settings__primary:hover:not(:disabled):not([aria-disabled="true"]) { border-color: var(--v2-ink-hover); background: var(--v2-ink-hover); } .v2-root button.v2-settings__secondary:hover:not(:disabled):not([aria-disabled="true"]) { border-color: var(--v2-border-strong); } .v2-root button.v2-settings__primary:focus-visible, .v2-root button.v2-settings__secondary:focus-visible { outline: none; border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-root button.v2-settings__primary:disabled, .v2-root button.v2-settings__secondary:disabled, .v2-root button.v2-settings__primary[aria-disabled="true"], .v2-root button.v2-settings__secondary[aria-disabled="true"] { cursor: default; opacity: 0.55; } .v2-settings__message { margin: 0 0 12px; color: var(--v2-text-secondary); font-size: 13px; line-height: 20px; } .v2-settings__message--error { color: var(--v2-text-primary); } /* D215 Settings › Look: a label and a segment per row. Language moved here from the rail (TASK-691). */ .v2-settings__look { display: flex; flex-direction: column; } .v2-settings__look-row { display: flex; min-height: 44px; align-items: center; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--v2-border-soft); } .v2-settings__look-row:last-child { border-bottom: 0; } .v2-settings__look-label { color: var(--v2-text-primary); font: 500 13px/18px var(--v2-font); } /* Settings owns the connected-apps controls without inheriting the legacy * page chrome: its section label is the only page-level heading. */ .v2-settings .apps-management--settings { color: var(--v2-text-primary); font-family: var(--v2-font); } .v2-settings .apps-management--settings .MuiCardContent-root { padding: 0; } .v2-settings .apps-management--settings .MuiCardActions-root { padding: 8px 0 0; } .v2-settings .apps-management--settings .apps-management__section + .apps-management__section { margin-top: 24px; padding-top: 24px; border-top: 1px solid var(--v2-border-soft); } .v2-settings .apps-management--settings .apps-management__integration { height: 100%; padding: 12px; border: 1px solid var(--v2-border); } .v2-settings .apps-management--settings .apps-management__developer-tips { margin: 14px 0 0; color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: var(--v2-fs-meta); line-height: var(--v2-lh-meta); } .v2-settings .apps-management--settings .MuiTypography-root, .v2-settings .apps-management--settings .MuiInputBase-input, .v2-settings .apps-management--settings .MuiInputLabel-root, .v2-settings .apps-management--settings .MuiButton-root { font-family: inherit; } .v2-settings .apps-management--settings .MuiSvgIcon-colorPrimary, .v2-settings .apps-management--settings .MuiButton-textPrimary { color: var(--v2-ink); } /* Cobalt remains a mark; buttons that commit a change are ink. */ .v2-settings .apps-management--settings .MuiButton-containedPrimary { border: 1px solid var(--v2-ink); border-radius: var(--v2-radius-sm); background: var(--v2-ink); color: var(--v2-on-ink); } .v2-settings .apps-management--settings .MuiButton-containedPrimary:hover { border-color: var(--v2-ink-hover); background: var(--v2-ink-hover); } @media (max-width: 560px) { .v2-settings .v2-devices__heading { display: flex; align-items: flex-start; } .v2-settings .v2-devices__heading > button { margin-left: auto; } } @media (max-width: 680px) { .v2-settings__layout { display: block; padding-top: 24px; } .v2-settings__title { margin-bottom: 24px; font-size: 28px; } .v2-settings__nav { display: none; } .v2-settings__section { padding: 20px 0; } .v2-settings__label { margin-bottom: 14px; } .v2-settings__token-value { grid-template-columns: 1fr 1fr; } .v2-settings__account-fields { grid-template-columns: 1fr; } .v2-settings__avatar-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); } .v2-root .v2-settings__avatar-actions button.v2-settings__secondary { min-height: 44px; } .v2-settings__avatar-footer { flex-direction: column; align-items: stretch; } .v2-settings__avatar-dialog-actions { width: 100%; gap: 8px; } .v2-root .v2-settings__avatar-dialog-actions button { flex: 1; min-width: 0; min-height: 44px; } .v2-settings__token-value code { grid-column: 1 / -1; } } /* ── V2 Pod Board — /v2/pods/:podId/board ──────────────────────────────── */ .v2-board { display: flex; flex-direction: column; height: 100%; min-height: 0; background: var(--v2-bg-subtle); } /* TASK-698: the board fills the pane and the columns scroll inside it. The feature body was the scroller and its legacy wrapper had auto height, so `height: 100%` and the column `max-height: 100%` resolved to nothing and the page grew to ~77,000px (85.5× at 1440, 97.9× at 390, measured by ux-lead at 12f608b71). Scoped to the board route so other feature pages keep their scroll. */ .v2-feature--board .v2-feature__body { display: flex; flex-direction: column; overflow: hidden; } /* margin auto stops a flex item stretching, so the board sized to its 1240px max-content width and ran off a 390px phone. An explicit width keeps it full width on a phone, and the auto margin still centres it on desktop. */ .v2-feature--board .v2-feature__legacy { flex: 1 1 auto; width: 100%; min-height: 0; margin: 0 auto; display: flex; flex-direction: column; } .v2-feature--board .v2-board { flex: 1 1 auto; height: auto; } .v2-board__head { display: flex; align-items: center; gap: 16px; padding: 14px 20px; background: var(--v2-bg); border-bottom: 1px solid var(--v2-border); } .v2-root button.v2-board__back { display: inline-flex; align-items: center; gap: 4px; border: none; background: none; color: var(--v2-text-secondary); font-size: 13px; font-weight: 500; cursor: pointer; padding: 6px 8px; border-radius: 6px; white-space: nowrap; } .v2-root button.v2-board__back:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-board__title-wrap { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 10px; } .v2-board__title { margin: 0; font-size: 16px; font-weight: 600; color: var(--v2-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-board__subtitle { font-size: 12.5px; color: var(--v2-text-tertiary); white-space: nowrap; } .v2-root button.v2-board__new { display: inline-flex; align-items: center; gap: 6px; border: none; background: var(--v2-ink); color: var(--v2-on-ink); font-size: 13px; font-weight: 600; padding: 8px 14px; border-radius: 8px; cursor: pointer; white-space: nowrap; } .v2-root button.v2-board__new:hover { background: var(--v2-ink-hover); } .v2-board__focus { margin: 16px 20px 0; padding: 16px 18px; border: 1px solid var(--v2-border); border-radius: 12px; background: var(--v2-bg); flex: 0 0 auto; /* A long focus list scrolls inside its own box, so the columns keep room below it on a short viewport (1440x560, 390x560). vh, not %: the board's height is auto, so a percentage would not resolve. */ max-height: min(35vh, 260px); overflow-y: auto; } .v2-board__focus-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; } .v2-board__focus-eyebrow { color: var(--v2-text-muted); font-size: 12px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; } .v2-board__focus-title { margin: 2px 0 0; color: var(--v2-text-primary); font-size: 16px; font-weight: 650; } .v2-root button.v2-board__focus-edit, .v2-root button.v2-board__focus-clear { min-height: 32px; border: 1px solid var(--v2-border); border-radius: 7px; padding: 5px 11px; color: var(--v2-text-secondary); background: var(--v2-surface); cursor: pointer; font-size: 12px; font-weight: 600; } .v2-root button.v2-board__focus-edit:hover, .v2-root button.v2-board__focus-clear:hover { border-color: var(--v2-border-strong); color: var(--v2-text-primary); background: var(--v2-surface-hover); } .v2-board__focus-muted, .v2-board__focus-error { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 10px; color: var(--v2-text-muted); font-size: 13px; } .v2-board__focus-error { color: var(--v2-danger, #b42318); } .v2-root button.v2-board__focus-retry, .v2-root button.v2-board__focus-review-latest { min-height: 32px; border: 1px solid var(--v2-border); border-radius: 7px; padding: 4px 10px; color: var(--v2-text-secondary); background: var(--v2-surface); cursor: pointer; font-size: 12px; font-weight: 600; } .v2-root button.v2-board__focus-retry:hover, .v2-root button.v2-board__focus-review-latest:hover:not(:disabled) { border-color: var(--v2-border-strong); color: var(--v2-text-primary); background: var(--v2-surface-hover); } .v2-root button.v2-board__focus-review-latest:disabled { color: var(--v2-text-muted); cursor: default; } .v2-board__focus-goal { margin: 10px 0 4px; color: var(--v2-text-primary); font-size: 16px; font-weight: 600; } .v2-board__focus-scope { margin: 0; color: var(--v2-text-secondary); font-size: 14px; line-height: 20px; white-space: pre-wrap; } .v2-board__focus-meta { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 10px; color: var(--v2-text-muted); font-size: 12px; } .v2-board__focus-meta strong { color: var(--v2-text-secondary); } .v2-board__focus-tasks { margin: 12px 0 0; padding-left: 24px; display: flex; flex-direction: column; gap: 6px; color: var(--v2-text-secondary); font-size: 13px; } .v2-board__focus-tasks li { display: flex; align-items: baseline; gap: 8px; min-width: 0; } .v2-board__focus-task-position { flex: 0 0 20px; color: var(--v2-text-muted); font-family: var(--v2-font-mono); font-size: 11px; text-align: right; } .v2-root button.v2-board__focus-task-link { border: 0; padding: 0; min-width: 0; color: var(--v2-accent-text); background: transparent; cursor: pointer; font: inherit; text-align: left; overflow-wrap: anywhere; } .v2-board__focus-task-title { min-width: 0; flex: 1 1 auto; overflow-wrap: anywhere; } .v2-root button.v2-board__focus-task-link:hover { text-decoration: underline; } .v2-board__focus-task-id { color: var(--v2-text-muted); font-family: var(--v2-font-mono); font-size: 11px; flex: 0 0 auto; } .v2-board__focus-task-status { color: var(--v2-text-muted); font-size: 12px; } .v2-board__focus-task-meta { display: flex; flex: 0 1 auto; flex-wrap: wrap; gap: 4px 8px; min-width: 0; margin-left: auto; } .v2-board__focus-task--unavailable { color: var(--v2-text-muted); font-style: italic; } .v2-board__focus-editor { width: min(640px, calc(100vw - 28px)); } .v2-board__focus-editor .v2-modal__close { min-width: 32px; min-height: 32px; } .v2-board__field textarea, .v2-board__field select { border: 1px solid var(--v2-border); border-radius: 8px; padding: 9px 12px; color: var(--v2-text-primary); background: var(--v2-bg); font: inherit; font-size: 13.5px; } .v2-board__field textarea:focus, .v2-board__field select:focus { outline: none; border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-board__focus-task-picker { max-height: 150px; overflow-y: auto; display: flex; flex-direction: column; gap: 6px; padding: 8px 10px; border: 1px solid var(--v2-border); border-radius: 8px; } .v2-board__focus-task-option { display: flex; align-items: flex-start; flex: 0 0 auto; gap: 8px; min-height: 32px; color: var(--v2-text-secondary); font-size: 12.5px; } .v2-board__focus-task-option input { flex: 0 0 auto; margin-top: 4px; } .v2-board__focus-task-option > span { flex: 1 1 auto; min-width: 0; line-height: 20px; overflow-wrap: anywhere; } .v2-board__focus-selected { margin: -3px 0 12px; padding-left: 22px; display: flex; flex-direction: column; gap: 5px; color: var(--v2-text-secondary); font-size: 12px; } .v2-board__focus-selected li { display: flex; align-items: center; flex-wrap: wrap; gap: 5px; } .v2-board__focus-selected li:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 2px; border-radius: 6px; } .v2-board__focus-selected li > span.v2-board__focus-position { flex: 0 0 20px; color: var(--v2-text-muted); font-family: var(--v2-font-mono); text-align: right; } .v2-board__focus-selected li > span.v2-board__focus-task-label { flex: 1 1 calc(100% - 25px); min-width: 0; } .v2-root .v2-board__focus-selected button { min-height: 32px; border: 1px solid var(--v2-border); border-radius: 7px; padding: 5px 10px; color: var(--v2-text-secondary); background: var(--v2-surface); cursor: pointer; font-size: 12px; } .v2-board__focus-selected button:hover:not(:disabled) { border-color: var(--v2-border-strong); color: var(--v2-text-primary); background: var(--v2-surface-hover); } .v2-board__focus-selected button:disabled { color: var(--v2-text-muted); cursor: default; } .v2-board__focus-live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; border: 0; } .v2-board__focus-actions { display: flex; justify-content: flex-end; gap: 8px; align-items: center; } .v2-root button.v2-board__focus-save { min-height: 32px; border: none; border-radius: 8px; padding: 9px 16px; color: var(--v2-on-ink); background: var(--v2-ink); cursor: pointer; font-size: 13.5px; font-weight: 600; } .v2-root button.v2-board__focus-save:not(:disabled):hover { background: var(--v2-ink-hover); } .v2-root button.v2-board__focus-save:disabled { opacity: 0.55; cursor: default; } .v2-board__focus-conflict { margin-top: 8px; padding: 10px 12px; border: 1px solid var(--v2-border); border-radius: 8px; background: var(--v2-surface-hover); color: var(--v2-text-secondary); font-size: 12px; line-height: 1.45; } .v2-board__focus-conflict h3 { margin: 0 0 6px; color: var(--v2-text-primary); font-size: 12px; } .v2-board__focus-conflict p { margin: 4px 0; } .v2-board__focus-conflict ol { margin: 6px 0 0; padding-left: 20px; } .v2-board__focus-conflict .v2-board__focus-review-latest { margin-top: 8px; } .v2-board__columns { display: flex; gap: 14px; padding: 16px 20px 24px; overflow-x: auto; overflow-y: hidden; flex: 1; min-height: 0; align-items: flex-start; } .v2-board__col { flex: 1 1 0; min-width: 230px; max-width: 340px; background: var(--v2-surface); border: 1px solid var(--v2-border); border-radius: 12px; padding: 12px; display: flex; flex-direction: column; gap: 10px; max-height: 100%; overflow-y: auto; } .v2-board__col-head { display: flex; align-items: center; justify-content: space-between; padding: 0 4px; } .v2-board__col-name { font-size: 12px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--v2-text-secondary); } .v2-board__col-count { color: var(--v2-text-secondary); font: 500 11px/16px var(--v2-font-mono); } .v2-board__col-empty { font-size: 13px; color: var(--v2-text-muted); padding: 14px 6px; text-align: center; flex-shrink: 0; } .v2-board__card { border: 1px solid var(--v2-border); border-radius: 10px; background: var(--v2-bg); overflow: hidden; flex-shrink: 0; } .v2-root button.v2-board__card-main { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; width: 100%; border: none; background: none; cursor: pointer; text-align: left; padding: 10px 12px 6px; } .v2-root button.v2-board__card-main:hover { background: var(--v2-surface-hover); } .v2-board__card-id { font-family: ui-monospace, 'SF Mono', Menlo, monospace; font-size: 10.5px; color: var(--v2-text-muted); letter-spacing: 0.03em; } .v2-board__card-title { font-size: 13.5px; font-weight: 500; color: var(--v2-text-primary); line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; } .v2-board__card-assignee { font-size: 12px; color: var(--v2-accent-text); font-weight: 500; } .v2-board__card-actions { display: flex; gap: 6px; padding: 4px 10px 10px; } .v2-root button.v2-board__card-move { border: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-secondary); min-height: 32px; font-size: 12px; font-weight: 600; border-radius: 6px; padding: 3px 10px; cursor: pointer; } .v2-root button.v2-board__card-move:hover { border-color: var(--v2-border-strong); color: var(--v2-text-primary); background: var(--v2-surface-hover); } .v2-board__detail-meta { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; } .v2-board__detail-pr { font-size: 12.5px; color: var(--v2-accent-text); font-weight: 500; } .v2-board__detail-notes { font-size: 13.5px; color: var(--v2-text-secondary); margin: 0 0 12px; white-space: pre-wrap; } .v2-board__detail-updates { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; max-height: 240px; overflow-y: auto; } .v2-board__detail-updates li { display: flex; flex-direction: column; gap: 1px; font-size: 12.5px; border-left: 3px solid var(--v2-border); padding-left: 10px; } .v2-board__detail-update-author { font-weight: 600; color: var(--v2-text-secondary); font-size: 11.5px; } .v2-board__detail-update-text { color: var(--v2-text-secondary); } .v2-board__field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; } .v2-board__field span { font-size: 12px; font-weight: 600; color: var(--v2-text-secondary); } .v2-board__field input { border: 1px solid var(--v2-border); border-radius: 8px; padding: 9px 12px; font-size: 13.5px; color: var(--v2-text-primary); background: var(--v2-bg); } .v2-board__field input:focus { outline: none; border-color: var(--v2-accent); box-shadow: var(--v2-focus-ring); } .v2-root button.v2-board__create-submit { border: none; background: var(--v2-accent-fill); color: var(--v2-on-accent); font-size: 13.5px; font-weight: 600; padding: 9px 16px; border-radius: 8px; cursor: pointer; } .v2-root button.v2-board__create-submit:disabled { opacity: 0.55; cursor: default; } .v2-root button.v2-board__create-submit:not(:disabled):hover { background: var(--v2-accent-strong); } @media (max-width: 760px) { /* At 390 the head was one nowrap row (back, subtitle, New task), which squeezed the title to under 1px. On a phone the title takes its own full-width row; back and New task share the row above it. */ .v2-board__head { flex-wrap: wrap; row-gap: 8px; padding: 12px 14px; gap: 10px; } .v2-board__title-wrap { order: 1; flex: 1 1 100%; } .v2-board__new { margin-left: auto; } /* The board is the phone's full-width surface. Its own head and columns carry the 14px inset, so the feature body does not add its 34px desktop gutter. */ .v2-feature--board > .v2-feature__body { padding: 0; } .v2-board__columns { padding: 12px 14px 20px; } .v2-board__focus { margin: 12px 14px 0; padding: 14px; } .v2-root button.v2-board__focus-edit, .v2-root button.v2-board__focus-clear, .v2-root button.v2-board__focus-retry, .v2-root button.v2-board__focus-review-latest, .v2-root .v2-board__focus-selected button { min-height: 44px; } .v2-board__focus-tasks li { display: grid; grid-template-columns: 24px minmax(0, 1fr); grid-template-areas: "position id" "title title" "meta meta"; align-items: center; gap: 4px 8px; min-height: 0; } .v2-board__focus-tasks { padding-left: 0; } .v2-board__focus-tasks li .v2-board__focus-task-position { grid-area: position; } .v2-board__focus-tasks li .v2-board__focus-task-id { grid-area: id; } .v2-board__focus-tasks li .v2-board__focus-task-title { grid-area: title; width: 100%; } .v2-board__focus-tasks li .v2-board__focus-task-meta { grid-area: meta; margin-left: 0; } .v2-root button.v2-board__focus-task-link { width: 100%; } .v2-root button.v2-board__focus-task-link { min-height: 44px; display: inline-flex; align-items: center; } .v2-board__focus-editor .v2-modal__close, .v2-board__focus-editor .v2-board__field input, .v2-board__focus-editor .v2-board__field textarea, .v2-board__focus-editor .v2-board__field select, .v2-root .v2-board__focus-editor button.v2-board__focus-save, .v2-board__focus-task-option { min-height: 44px; } .v2-board__focus-task-option { height: auto; align-items: flex-start; padding: 8px 0; } .v2-board__col { min-width: 250px; max-width: none; flex: 0 0 78vw; } } /* ── Approval card (ADR-020 D3 / ADR-017) ────────────────────────────────── Speaks the Signal needs-you idiom: white ground + cobalt 2px ring. The ring identifies an unresolved human decision without turning the card into generic tinted chrome. */ /* The card sits IN the message content column, not flush with the row edge: 38px avatar column + 12px gap, in lockstep with the .v2-msg grid. Without this inset the card starts 50px left of every bubble's text and reads as misaligned (measured 372 vs 422, 2026-08-13). */ .v2-msg.v2-msg--card { padding-left: 50px; } .v2-gig { min-width: 0; max-width: 600px; padding: 12px 16px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); background: var(--v2-surface); color: var(--v2-text-primary); overflow-wrap: anywhere; } .v2-gig__head, .v2-gig__stack, .v2-gig__kv { display: flex; gap: 8px; align-items: baseline; } .v2-gig__head { justify-content: space-between; font: 500 11px var(--v2-font-mono); color: var(--v2-text-muted); margin-bottom: 8px; } .v2-gig__stack { flex-wrap: wrap; align-items: center; margin-bottom: 8px; } .v2-gig__badge { font: 500 11px var(--v2-font-mono); border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); padding: 2px 5px; white-space: nowrap; } .v2-gig__text { font-size: 14px; line-height: 1.45; font-weight: 600; min-width: 0; } .v2-gig__kv { font-size: 12px; color: var(--v2-text-secondary); margin-bottom: 8px; flex-wrap: wrap; } .v2-gig__kv strong { color: var(--v2-text-primary); font-weight: 500; } .v2-gig__list { margin: 0 0 8px; padding-left: 20px; } .v2-gig__link { color: var(--v2-accent-text); text-decoration: underline; text-underline-offset: 2px; font-size: 12px; } .v2-gig__link:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } @media (max-width: 760px) { .v2-msg.v2-msg--card:has(.v2-gig) { padding-left: 0; } } .v2-approval { border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); background: var(--v2-surface); box-shadow: 0 0 0 2px var(--v2-accent); padding: 12px 16px; max-width: none; display: flex; flex-direction: column; gap: 8px; } .v2-approval__head { display: flex; align-items: center; gap: 8px; } .v2-approval__badge { font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--v2-ink); font-family: var(--v2-font-mono); } .v2-approval__agent { font-size: 12.5px; font-weight: 600; color: var(--v2-text-secondary); } .v2-approval__time { font-size: 11.5px; color: var(--v2-text-muted); margin-left: auto; } .v2-approval__summary { font-size: 14px; color: var(--v2-text-primary); line-height: 1.45; } /* The consent line — server-derived from actionType + params. It outranks the agent's prose deliberately: the prose is unvalidated and the human is consenting to what executes, not to what was pitched. */ .v2-approval__action { font-size: 14.5px; font-weight: 600; color: var(--v2-text-primary); line-height: 1.4; overflow-wrap: anywhere; } /* Owner-only canonical tool arguments. Keep the exact JSON readable without letting a long comment body widen the message column on mobile. */ .v2-approval__tool-call { margin: 0; padding: 8px 10px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); background: var(--v2-bg); color: var(--v2-text-primary); font: 12px/1.45 var(--v2-font-mono); white-space: pre-wrap; overflow-wrap: anywhere; overflow-x: auto; } /* The agent's reason for asking, demoted below the action it belongs to. */ .v2-approval__pitch { font-size: 13px; color: var(--v2-text-secondary); line-height: 1.45; padding-left: 10px; border-left: 2px solid var(--v2-border-soft); overflow-wrap: anywhere; } .v2-approval__actions { display: flex; gap: 8px; margin-top: 2px; } .v2-root button.v2-approval__btn { border-radius: var(--v2-radius-sm); font-size: 13px; font-weight: 600; padding: 7px 16px; cursor: pointer; border: 1px solid var(--v2-border); } .v2-root button.v2-approval__btn--approve { background: var(--v2-ink); border-color: var(--v2-ink); color: var(--v2-on-ink); } .v2-root button.v2-approval__btn--approve:not(:disabled):hover { background: var(--v2-ink-hover); } .v2-root button.v2-approval__btn--decline { background: var(--v2-bg); color: var(--v2-text-secondary); } .v2-root button.v2-approval__btn--decline:not(:disabled):hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-approval__btn:disabled { opacity: 0.55; cursor: default; } .v2-approval__state { font-size: 13px; color: var(--v2-text-secondary); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .v2-approval__state--approved { color: #047857; font-weight: 600; } .v2-approval__state--declined { color: var(--v2-text-tertiary); font-weight: 600; } .v2-approval__state--attention { color: #b45309; font-weight: 600; } .v2-approval__state--expired { color: var(--v2-text-muted); font-style: italic; } .v2-root button.v2-approval__result-link { border: none; background: none; color: var(--v2-accent-text); font-size: 13px; font-weight: 600; cursor: pointer; padding: 0; text-decoration: underline; } .v2-approval__error { font-size: 12.5px; color: #b91c1c; } /* Hosted-to-BYO handoff: the command is server-composed and the card copies the selected string verbatim. Keep it visually distinct from approval cards without making the shell instructions look like ordinary agent prose. */ .v2-byo-handoff { border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); background: var(--v2-surface); box-shadow: 0 0 0 2px var(--v2-accent); padding: 12px 16px; display: flex; flex-direction: column; gap: 8px; } .v2-byo-handoff__head { display: flex; align-items: center; gap: 8px; } .v2-byo-handoff__badge { font-size: 11px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--v2-ink); font-family: var(--v2-font-mono); } .v2-byo-handoff__agent, .v2-byo-handoff__time { font-size: 12.5px; color: var(--v2-text-secondary); } .v2-byo-handoff__time { margin-left: auto; font-size: 12px; color: var(--v2-text-muted); } .v2-byo-handoff__title { font-size: 15px; font-weight: 650; color: var(--v2-text-primary); } .v2-byo-handoff__body, .v2-byo-handoff__note { font-size: 13px; color: var(--v2-text-secondary); line-height: 1.45; } .v2-byo-handoff__os { display: flex; gap: 6px; flex-wrap: wrap; } .v2-root button.v2-byo-handoff__os-btn, .v2-root button.v2-byo-handoff__copy { border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); font-size: 13px; font-weight: 600; cursor: pointer; } .v2-root button.v2-byo-handoff__os-btn { padding: 6px 10px; background: var(--v2-bg); color: var(--v2-text-secondary); } .v2-root button.v2-byo-handoff__os-btn--selected { background: var(--v2-ink); border-color: var(--v2-ink); color: var(--v2-on-ink); } .v2-byo-handoff__command { margin: 0; padding: 10px 12px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); background: var(--v2-bg); color: var(--v2-text-primary); font: 12px/1.5 var(--v2-font-mono); white-space: pre-wrap; overflow-wrap: anywhere; overflow-x: auto; } .v2-root button.v2-byo-handoff__copy { align-self: flex-start; padding: 7px 14px; background: var(--v2-ink); border-color: var(--v2-ink); color: var(--v2-on-ink); } .v2-root button.v2-byo-handoff__copy:hover:not(:disabled) { background: var(--v2-ink-hover); } .v2-root button.v2-byo-handoff__copy:disabled { opacity: 0.55; cursor: default; } /* Inspector pending-approvals index (durable, row-backed — cards in chat retire with message retention; this list never does). */ .v2-inspector__approvals { display: flex; flex-direction: column; gap: 10px; } .v2-inspector__approval-row { border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); background: var(--v2-surface); box-shadow: 0 0 0 2px var(--v2-accent); padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; } .v2-inspector__approval-summary { font-size: 13px; color: var(--v2-text-primary); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .v2-inspector__approval-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; } .v2-inspector__approval-agent { font-size: 12px; font-weight: 600; color: var(--v2-text-secondary); } .v2-inspector__approval-actions { display: flex; gap: 6px; } .v2-inspector__approval-waiting { font-size: 12px; color: var(--v2-text-muted); font-style: italic; } /* ── Threading: headline card + reply rail (W-T 4/4) ──────────────────────── Built to @ux-lead's render brief. Numbers here are theirs, not invented: NOTE the `.v2-root button.` prefix on every button rule below. It keeps the card's interactive treatment explicit while the global reset remains a low-specificity default. This used to be a specificity workaround for a real-browser defect: computed colour was rgb(17,24,39) while the rule said #4b5563 — which no presence guard can see, because the rule IS present. card radius 10 / border #e5e7eb / hover #d7dce7 / no shadow; type 13px secondary with the count at 500; rail 2px #eef0f6 at 28px, replies +40px, dropping to 24px at 390; layout transition 300ms. */ /* Card + rail travel as ONE column row, indented to the message TEXT column like an attachment (2026-08-23): 38px avatar column + 12px gap = 50px, so the thread visibly belongs to the message above it rather than starting a new row at the avatar edge. The bottom margin is the rail's terminator: without it the rail's last pixel abuts the next outer message and reads as connected to it. */ .v2-thread-block { margin-left: 50px; /* The column's `> *` rule sets width: 100%; with the 50px indent that put every thread 50px past the pane's right edge — the pane became horizontally swipeable, worst on phones (2026-08-24; measured scrollWidth 350 vs clientWidth 326 at 390px). Indent + width must sum to 100%. */ width: calc(100% - 50px); margin-bottom: 14px; } .v2-thread-card { display: flex; align-items: center; gap: 8px; margin: 4px 0 0 0; /* brief: no gap > 8px between root and card */ } .v2-root button.v2-thread-card__main { display: flex; align-items: center; gap: 10px; min-height: 44px; /* brief: 44px min hit height */ padding: 6px 12px; border: 1px solid #e5e7eb; border-radius: 10px; background: transparent; box-shadow: none; cursor: pointer; font-size: 13px; color: #4b5563; transition: border-color 300ms ease; } .v2-root button.v2-thread-card__main:hover { border-color: #d7dce7; } /* This is deliberately outside the expand button: it must aim the composer without toggling the rail, and nested controls are invalid HTML. */ .v2-thread-card__count { font-weight: 500; display: inline-flex; align-items: center; gap: 6px; } /* The card's ONLY accent, and only when something in the thread addresses me. Ambient activity never colours it — that is the whole point of 3/4's ambient/addressed split being visible in the UI rather than only in the wake path. */ .v2-thread-card--addressed .v2-thread-card__count { color: var(--v2-accent); } .v2-thread-card__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--v2-accent); } .v2-thread-card__faces { display: inline-flex; } .v2-thread-card__faces > * + * { margin-left: -6px; /* brief: overlapping −6px */ } .v2-thread-card__time { color: #7b8494; } /* Expanded replies hang off a left rail at the thread block's own edge. The rail used to aim at the root avatar's centre (margin-left 14, rev 2); with the whole block indented to the text column like an attachment (2026-08-23), the rail sits AT that column edge — margin 0 — so card, rail, and message text share one line. */ .v2-thread-replies { position: relative; margin-left: 0; padding-left: 12px; border-left: 2px solid #eef0f6; transition: height 300ms ease; } /* Replies are SMALLER rows, not channel rows. Reusing the channel's 38px + 12px column opened a second text column 70px right of the root's — two columns and an off-axis rail was the raggedness. One inner column: 16 (rail) + 12 (padding) + 24 (sm avatar) + 8 (gap) = x = 60, the same for every reply, grouped or not. */ .v2-thread-replies .v2-msg { grid-template-columns: 24px minmax(0, 1fr); gap: 8px; padding: 6px 0; } .v2-thread-replies .v2-msg:first-child { margin-top: 4px; } .v2-thread-replies .v2-msg--grouped { padding: 2px 0; } /* Tighter head inside the rail. The root keeps 700 — weight is hierarchy, so the reply author must not match it. */ .v2-thread-replies .v2-msg__head { height: 18px; } .v2-thread-replies .v2-msg__author { font-size: 13px; font-weight: 600; } .v2-thread-replies .v2-msg__time { font-size: 12px; } .v2-root button.v2-thread-replies__aim { border: none; background: transparent; color: #7b8494; font-size: 12px; cursor: pointer; /* Same x = 60 column as every reply: 24px avatar + 8px gap of dead space, so it reads as an affordance on the column rather than a message. */ margin-left: 32px; padding: 8px 0 4px; } .v2-root button.v2-thread-replies__aim:hover { background: var(--v2-surface-hover); } .v2-chat__reply-chip--thread .v2-chat__reply-chip-label { color: #4b5563; } @media (max-width: 640px) { /* Touch has no hover: the action cluster appears on TAP-REVEAL (.v2-msg--reveal, set by the bubble's tap handler) with 44px targets — never by default; always-on clusters over every message are chrome over content. The old inline head buttons this block used to force visible were retired 2026-08-23. */ .v2-msg__head { height: auto; flex-wrap: wrap; } .v2-msg--reveal .v2-msg__actions { opacity: 1; pointer-events: auto; } .v2-root button.v2-msg__action { width: 44px; height: 44px; } .v2-thread-card { flex-wrap: wrap; } /* Reply in thread / Follow / Collapse left the chip for the band's foot (ux-lead 64476 (3)); the 44px touch floor follows them. */ .v2-root .v2-thread-replies__foot button { min-height: 44px; } /* The block's 50px attachment indent is expensive at 390 — tighten it, but keep the rail on the block edge (aligned with the card), and the inner padding tightens with it. */ .v2-thread-block__inner { margin-left: 24px; } .v2-thread-replies { margin-left: 0; padding-left: 8px; } .v2-root button.v2-thread-card__main { flex: 1 1 100%; flex-wrap: wrap; /* brief: card goes to two lines at 390 */ } } /* Activity is a feature-wide read surface: short attention rows first, then evidence of agent work and board movement. Every grid child is min-width:0 so a long pod or task title cannot create horizontal scroll at 390px. */ .v2-activity { width: min(100%, 1120px); margin: 0 auto; padding: 8px 0 28px; } .v2-activity__header { display: flex; align-items: end; justify-content: space-between; gap: 24px; padding-bottom: 24px; border-bottom: 1px solid var(--v2-border-soft); } .v2-activity__title, .v2-activity__section h2, .v2-activity__agent-card h3, .v2-activity__board-row h3 { margin: 0; color: var(--v2-text-primary); } .v2-activity__title { font-size: clamp(26px, 3vw, 34px); font-weight: 700; /* 850 was tuned for SF Pro Display; Inter reads right at 700 */ line-height: 1.08; letter-spacing: -0.03em; } .v2-activity__controls, .v2-activity__window, .v2-activity__agent-topline, .v2-activity__board-meta { display: flex; align-items: center; } .v2-activity__controls { gap: 8px; flex-shrink: 0; } .v2-activity__window { gap: 2px; padding: 3px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); } .v2-root button.v2-activity__window-button { min-height: 30px; padding: 0 10px; white-space: nowrap; border-radius: calc(var(--v2-radius-sm) - 2px); color: var(--v2-text-secondary); font-size: 12px; font-weight: 600; } .v2-root button.v2-activity__window-button--active { background: var(--v2-surface-hover); color: var(--v2-text-primary); font-weight: 600; box-shadow: none; } .v2-activity__scope select { min-height: 36px; max-width: 180px; padding: 0 30px 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); font: inherit; font-size: 12px; } .v2-activity__loading, .v2-activity__error, .v2-activity__empty { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 118px; gap: 4px; padding: 20px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); color: var(--v2-text-secondary); text-align: center; font-size: 13px; line-height: 1.55; } .v2-activity__error { margin-top: 20px; border-color: var(--v2-danger); background: var(--v2-danger-soft); color: var(--v2-text-primary); } .v2-activity__sections { display: grid; gap: 38px; margin-top: 30px; } /* Composer (ruled 2026-09-03 on the Shell Parity canvas, board 3): one card, radius-lg, the textarea borderless inside it, a small ink Send in the foot row. Focus is the halo on the CARD, not a harder border. */ .v2-activity__compose { display: flex; flex-direction: column; gap: 8px; margin-top: 22px; padding: 12px 14px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-lg); background: var(--v2-surface); transition: box-shadow 120ms ease; } .v2-activity__compose:focus-within { box-shadow: 0 0 0 4px rgba(29, 63, 209, 0.10); } .v2-activity__compose-top, .v2-activity__compose-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; } .v2-activity__compose-pod { display: inline-flex; align-items: center; gap: 6px; color: var(--v2-text-muted); font-size: var(--v2-fs-meta); line-height: var(--v2-lh-meta); } .v2-activity__compose-picker { position: relative; min-width: 0; } .v2-root .v2-activity__compose-picker-button { height: 26px; min-height: 26px; max-width: 220px; overflow: hidden; padding: 0 24px 0 8px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); font: inherit; font-size: var(--v2-fs-meta); font-weight: 500; text-overflow: ellipsis; white-space: nowrap; } .v2-activity__compose-picker-menu { position: absolute; z-index: 4; top: calc(100% + 4px); right: 0; display: grid; min-width: 180px; max-width: min(280px, 70vw); padding: 4px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); box-shadow: var(--v2-shadow-md); } .v2-root .v2-activity__compose-picker-option { min-height: 30px; padding: 5px 8px; border: 0; border-radius: 3px; background: transparent; color: var(--v2-text-primary); text-align: left; font: inherit; font-size: var(--v2-fs-meta); font-weight: 500; } .v2-root .v2-activity__compose-picker-option:hover, .v2-root .v2-activity__compose-picker-option.is-active { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root .v2-activity__compose textarea { width: 100%; min-width: 0; resize: none; padding: 2px 0; border: none; border-radius: 0; background: transparent; color: var(--v2-text-primary); font: inherit; font-size: var(--v2-fs-body); line-height: var(--v2-lh-body); } /* Halo focus (TASK-122): the card carries the halo (focus-within above), so the textarea itself shows nothing; the destination picker carries its own ring. */ .v2-root .v2-activity__compose textarea:focus-visible { outline: none; box-shadow: none; border-color: transparent; } .v2-activity__compose-picker-button:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); border-color: var(--v2-accent); } .v2-root .v2-activity__compose-picker-button:hover:not(:disabled) { border-color: var(--v2-border-strong); background: var(--v2-surface-hover); } .v2-activity__compose-hint { color: var(--v2-text-muted); font-size: var(--v2-fs-meta); line-height: var(--v2-lh-meta); } .v2-root .v2-activity__compose button { min-height: 30px; padding: 0 14px; border: 1px solid var(--v2-ink); border-radius: var(--v2-radius-sm); background: var(--v2-ink); color: var(--v2-on-ink); font-size: 13px; font-weight: 600; } .v2-root .v2-activity__compose button:hover:not(:disabled) { border-color: var(--v2-ink-hover); background: var(--v2-ink-hover); } /* The destination menu is a light, bounded list even though its options are buttons nested under the composer. Keep this selector stronger than the generic Send-button rule above so a large pod list cannot become a black, unbounded wall of buttons. */ .v2-root .v2-activity__compose .v2-activity__compose-picker-menu { max-height: 240px; overflow-y: auto; } .v2-root .v2-activity__compose .v2-activity__compose-picker-option { min-height: 30px; padding: 5px 8px; border: 0; border-radius: 3px; background: transparent; color: var(--v2-text-primary); text-align: left; font: inherit; font-size: var(--v2-fs-meta); font-weight: 500; } .v2-root .v2-activity__compose .v2-activity__compose-picker-option.is-active { border-color: transparent; background: var(--v2-surface-hover); color: var(--v2-text-primary); } /* The generic composer hover rule includes :not(:disabled) and a button element, so it outranks the picker option's class-only hover selector. Match that specificity here to keep the light Signal option treatment in the real hovered and selected+hovered states without changing Send. */ .v2-root .v2-activity__compose .v2-activity__compose-picker-menu button.v2-activity__compose-picker-option:hover:not(:disabled) { border-color: transparent; background: var(--v2-surface-hover); color: var(--v2-text-primary); } /* The generic composer button treatment above is for Send. The destination picker is a neutral selector and needs a stronger selector so it cannot inherit Send's ink fill. */ .v2-root .v2-activity__compose .v2-activity__compose-picker-button { border: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-primary); } .v2-root .v2-activity__compose .v2-activity__compose-picker-button:hover:not(:disabled) { border-color: var(--v2-border-strong); background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root .v2-activity__compose .v2-activity__compose-picker-button:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); border-color: var(--v2-accent); } .v2-activity__section-heading { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; } .v2-activity__count { color: var(--v2-text-secondary); font: 500 11px/16px var(--v2-font-mono); } .v2-activity__eyebrow { margin-bottom: 5px; color: var(--v2-text-muted); font-size: 11px; font-family: var(--v2-font-mono); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; } .v2-activity__section h2 { margin: 0; font-size: 15px; line-height: 20px; font-weight: 600; letter-spacing: 0; } .v2-activity__board-list { border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius); overflow: hidden; } /* Needs-you rows: no box, no dividers (TASK-122). Each row carries a permanent transparent 1px border and changes only its fill on hover, so nothing shifts by a pixel. Board rows keep their box until Phase B. */ .v2-activity__queue { display: grid; gap: 2px; } .v2-activity__queue-more { justify-self: start; min-height: 36px; margin-top: 8px; padding: 0 12px; border: 1px solid var(--v2-accent); border-radius: var(--v2-radius-sm); background: transparent; color: var(--v2-accent-text); font: 600 12px/16px var(--v2-font); } .v2-activity__queue-more:hover:not(:disabled) { background: var(--v2-accent-soft); } .v2-activity__queue-more:disabled { opacity: 0.65; cursor: default; } .v2-activity__board-row { display: grid; align-items: center; gap: 14px; min-width: 0; padding: 15px 16px; background: var(--v2-surface); } .v2-activity__board-row + .v2-activity__board-row { border-top: 1px solid var(--v2-border-soft); } .v2-activity__queue-row { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; align-items: start; gap: 12px; min-width: 0; padding: 11px 13px; border: 2px solid var(--v2-accent); border-radius: var(--v2-radius); background: var(--v2-surface); transition: background 80ms ease; } .v2-activity__queue-row:hover { background: var(--v2-surface); } /* Decision elevation: a pending decision or approval sits one step above the settled rows — the one shadow allowed on a chrome card, and only while pending. Hover does not move it; it is already up. */ .v2-activity__queue-row--decision, .v2-activity__queue-row--approval { background: var(--v2-surface); border-color: var(--v2-accent); border-radius: var(--v2-radius); box-shadow: none; } .v2-activity__queue-row--decision:hover, .v2-activity__queue-row--approval:hover { background: var(--v2-surface); } /* A ruled decision has settled: it drops back to the flat row. */ .v2-activity__queue-row--settled { background: transparent; border: 1px solid var(--v2-border); padding: 12px 14px; box-shadow: none; } .v2-activity__queue-row--settled:hover { background: var(--v2-surface-hover); } .v2-activity__queue-mark { display: grid; width: 28px; height: 28px; place-items: center; border-radius: var(--v2-radius-sm); background: var(--v2-accent-soft); color: var(--v2-accent-text); font-size: 12px; font-weight: 700; } .v2-activity__queue-row--decision .v2-activity__queue-mark { background: var(--v2-ink); color: var(--v2-on-ink); } .v2-activity__queue-row--approval .v2-activity__queue-mark { background: var(--v2-warning-soft); color: #a85d08; } .v2-activity__queue-row--onboarding .v2-activity__queue-mark { background: var(--v2-surface-hover); color: var(--v2-text-primary); } /* One seat, one mark everywhere: the chat's cobalt agent mark and tint human mark. */ .v2-activity__queue-row .v2-activity__queue-mark--agent { background: var(--v2-accent); color: var(--v2-on-ink); font: 600 12px/16px var(--v2-font); } .v2-activity__queue-row .v2-activity__queue-mark--human { background: var(--v2-surface-hover); color: var(--v2-text-primary); font: 600 12px/16px var(--v2-font); } .v2-activity__queue-copy, .v2-activity__board-main > div, .v2-activity__agent-card, .v2-activity__agent-topline > div { min-width: 0; } .v2-activity__queue-kind, .v2-activity__queue-copy > span, .v2-activity__queue-topline > span, .v2-activity__agent-topline span, .v2-activity__board-meta, .v2-activity__task-id, .v2-activity__update-time { color: var(--v2-text-muted); font-size: var(--v2-fs-meta); line-height: var(--v2-lh-meta); } .v2-activity__queue-copy strong, .v2-activity__queue-copy p, .v2-activity__board-row h3, .v2-activity__board-row p, .v2-activity__update-content { overflow-wrap: anywhere; } .v2-activity__queue-kind { font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-secondary); } .v2-activity__queue-copy strong { display: block; margin-top: 2px; color: var(--v2-text-primary); font-size: var(--v2-fs-body); line-height: var(--v2-lh-body); } .v2-activity__queue-copy p, .v2-activity__board-row p { margin: 3px 0; color: var(--v2-text-secondary); font-size: var(--v2-fs-body); line-height: var(--v2-lh-body); } /* Activity details stay compact until the reader hovers, focuses, or taps to expand them. The button keeps the full copy available without adding a permanent paragraph to every queue row. */ .v2-root .v2-activity__queue-detail { display: -webkit-box; min-height: 0; max-width: 100%; margin: 3px 0; padding: 0; border: 0; border-radius: 0; background: transparent; color: var(--v2-text-secondary); font: 400 var(--v2-fs-body)/var(--v2-lh-body) var(--v2-font); text-align: left; white-space: normal; overflow: hidden; overflow-wrap: anywhere; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } .v2-root button.v2-activity__queue-detail { color: var(--v2-text-secondary); } .v2-root .v2-activity__queue-row--mention .v2-activity__queue-detail { color: var(--v2-text-primary); } /* Focus previews the full copy (Tab in), but a detail the reader just collapsed is marked --dismissed and stays closed while focus remains on it, so aria-expanded and the visible copy agree. Blur clears the mark. */ .v2-root .v2-activity__queue-detail:focus-visible:not(.v2-activity__queue-detail--dismissed), .v2-root .v2-activity__queue-detail--expanded { display: block; overflow: visible; -webkit-line-clamp: unset; } /* Pointer hover is only a reveal affordance on devices that have hover. A focused button is intentionally excluded: after a pointer click the focus must not keep a second click from collapsing the detail again. */ @media (hover: hover) { .v2-root .v2-activity__queue-detail:hover:not(:focus) { display: block; overflow: visible; -webkit-line-clamp: unset; } } .v2-activity__queue-actions, .v2-activity__queue-row button, .v2-activity__board-meta button { display: flex; align-items: center; gap: 6px; } .v2-activity__queue-row button, .v2-activity__board-meta button { min-height: 30px; padding: 0 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); color: var(--v2-text-primary); font-size: 13px; font-weight: 600; } .v2-root .v2-activity__queue-actions button { min-height: 32px; padding: 0 12px; white-space: nowrap; border-color: var(--v2-ink); background: var(--v2-ink); color: var(--v2-on-ink); transition: background 80ms ease, border-color 80ms ease, color 80ms ease; } .v2-root .v2-activity__queue-actions button:hover:not(:disabled) { border-color: var(--v2-ink-hover); background: var(--v2-ink-hover); } .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--secondary { border-color: var(--v2-border); background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--secondary:hover:not(:disabled) { border-color: var(--v2-border-strong); background: var(--v2-surface); color: var(--v2-text-primary); } .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--thread { padding-inline: 4px; border-color: transparent; background: transparent; color: var(--v2-accent-text); } .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--thread:hover:not(:disabled) { border-color: transparent; background: var(--v2-accent-soft); color: var(--v2-accent-text); } /* Activity's navigation and acknowledgement controls are secondary actions: keep them visibly distinct from the ink send/approve actions while making their hit targets as clear as the approved board. */ .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--bordered { padding-inline: 12px; border: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-primary); } .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--bordered:hover:not(:disabled) { border: 1px solid var(--v2-border-strong); background: var(--v2-surface-hover); color: var(--v2-text-primary); } /* DecisionRequest alternatives are content, not row actions: a decision gets its own full-width action line below the question. Preserve the asking agent's option order; only the first authored option receives the cobalt primary treatment. */ .v2-activity__queue-row--decision .v2-activity__queue-actions { grid-column: 1 / -1; justify-content: flex-start; flex-wrap: wrap; } /* Mention rows (canvas board 3): the reply line sits UNDER the message, indented past the mark, never squeezed beside it. The mark already says "@", so the kind label is redundant and hidden. */ .v2-activity__queue-row--mention { align-items: start; } .v2-activity__queue-topline { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0; } .v2-activity__queue-topline strong { margin-top: 0; font-weight: 600; } .v2-activity__queue-row--mention .v2-activity__queue-copy p { color: var(--v2-text-primary); } .v2-activity__queue-row--mention .v2-activity__queue-actions { grid-column: 2 / -1; align-items: center; margin-top: 4px; } .v2-root .v2-activity__queue-actions button:disabled { opacity: 0.7; cursor: default; } .v2-root .v2-activity__queue-actions button.v2-activity__option { border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); } .v2-root .v2-activity__queue-actions button.v2-activity__option--primary { border-color: var(--v2-accent); background: var(--v2-accent); color: var(--v2-on-ink); } .v2-root .v2-activity__queue-actions button.v2-activity__option--primary:hover:not(:disabled) { border-color: var(--v2-accent-strong); background: var(--v2-accent-strong); color: var(--v2-on-ink); } .v2-root .v2-activity__queue-actions button.v2-activity__option.v2-activity__queue-action--secondary { border: 0; background: transparent; color: var(--v2-accent-text); } .v2-activity__option-choice { display: grid; flex: 0 1 220px; min-width: 0; gap: 4px; } .v2-activity__option-choice button { width: 100%; justify-content: center; } .v2-activity__option-description { color: var(--v2-text-muted); font-size: 12px; line-height: 1.35; } .v2-activity__option-recommended, .v2-decision-card__option-recommended { font: 500 11px/14px var(--v2-font-mono); opacity: 0.9; } .v2-activity__decision-other { display: grid; grid-template-columns: minmax(0, 1fr) auto; flex-basis: 100%; gap: 8px; align-items: end; } .v2-activity__decision-other textarea { width: 100%; min-height: 44px; resize: vertical; padding: 8px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); font-size: 13px; line-height: 1.4; } .v2-activity__decision-ruled { color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; } .v2-activity__action-error { margin-top: 10px; color: var(--v2-danger); font-size: 13px; } .v2-root .v2-activity__row-action-error { grid-column: 1 / -1; color: var(--v2-ink); } .v2-activity__queue-row button:disabled, .v2-activity__updates button:disabled { cursor: default; opacity: 0.55; } .v2-activity__agent-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } .v2-activity__agent-card { padding: 16px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); } .v2-activity__agent-topline { gap: 10px; } .v2-activity__agent-topline h3 { font-size: 14px; } .v2-activity__agent-topline > div > span { display: block; margin-top: 2px; } .v2-activity__count-chip, .v2-activity__status { display: inline-flex; align-items: center; border-radius: 999px; font-size: 11px; font-family: var(--v2-font-mono); font-weight: 700; white-space: nowrap; } .v2-activity__count-chip { margin-left: auto; padding: 4px 7px; background: var(--v2-surface-hover); color: var(--v2-text-secondary); } .v2-activity__agent-recap { margin: 14px 0 10px; color: var(--v2-text-secondary); font-size: 13px; line-height: 1.55; } .v2-activity__updates { display: grid; gap: 2px; } .v2-root .v2-activity__updates button { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 7px; min-width: 0; padding: 7px 0; color: var(--v2-text-secondary); font-size: 12px; text-align: left; } .v2-root .v2-activity__updates button:hover:not(:disabled) { color: var(--v2-text-primary); } .v2-activity__update-pod { color: var(--v2-accent-text); font-weight: 700; white-space: nowrap; } .v2-activity__update-content { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-activity__board-row { grid-template-columns: minmax(0, 1fr) auto; } .v2-activity__board-main { display: flex; align-items: flex-start; gap: 10px; min-width: 0; } .v2-activity__status { flex-shrink: 0; padding: 4px 7px; background: var(--v2-surface-hover); color: var(--v2-text-secondary); } .v2-activity__status--done { background: var(--v2-success-soft); color: #087946; } .v2-activity__status--blocked { background: var(--v2-danger-soft); color: #b42318; } .v2-activity__status--claimed { background: var(--v2-accent-soft); color: var(--v2-accent-text); } .v2-activity__task-id { display: block; margin-bottom: 2px; font-weight: 700; } .v2-activity__board-row h3 { font-size: 14px; } .v2-activity__board-meta { justify-content: flex-end; gap: 9px; white-space: nowrap; } .v2-activity__footer { margin-top: 34px; color: var(--v2-text-muted); font-size: 12px; line-height: 1.5; text-align: center; } @media (max-width: 640px) { .v2-activity { padding-top: 0; } .v2-activity__header, .v2-activity__section-heading { align-items: baseline; flex-direction: row; flex-wrap: wrap; gap: 8px; } .v2-activity__controls { display: grid; grid-template-columns: minmax(0, 1fr) 110px; width: 100%; } .v2-activity__window { width: 100%; } .v2-root button.v2-activity__window-button { flex: 1 1 0; } .v2-activity__scope select { width: 100%; max-width: none; } .v2-activity__compose-top { align-items: flex-start; flex-direction: column; gap: 8px; } .v2-activity__compose-pod { width: 100%; } .v2-activity__compose-pod > span { white-space: nowrap; } .v2-activity__compose-picker { flex: 1 1 auto; min-width: 0; width: 100%; } .v2-root .v2-activity__compose-picker-button { width: 100%; max-width: none; text-align: left; } .v2-root .v2-activity__compose button { min-height: 44px; padding: 0 18px; } /* The picker option rule is more specific than the generic composer button floor above; repeat the menu scope so every option keeps a 44px touch target on phones. */ .v2-root .v2-activity__compose .v2-activity__compose-picker-menu .v2-activity__compose-picker-option { min-height: 44px; } .v2-activity__section-heading { flex-wrap: wrap; } .v2-activity__agent-grid { grid-template-columns: minmax(0, 1fr); } .v2-activity__queue-row { grid-template-columns: 28px minmax(0, 1fr); } .v2-activity__board-row { grid-template-columns: minmax(0, 1fr); } .v2-activity__queue-row > button, .v2-activity__queue-actions { grid-column: 2; } .v2-activity__queue-actions { flex-wrap: wrap; } /* Options are one-tap decisions. Keep their touch targets honest even when a 390px viewport makes the pills wrap onto separate rows. */ .v2-root .v2-activity__queue-actions button { min-height: 44px; } .v2-activity__option-choice { flex-basis: min(100%, 220px); } .v2-activity__decision-other { grid-template-columns: minmax(0, 1fr); } .v2-activity__board-meta { grid-column: 1; justify-content: flex-start; flex-wrap: wrap; } .v2-activity__update-time { display: none; } } @media (prefers-reduced-motion: reduce) { .v2-root button.v2-thread-card__main, .v2-thread-replies { transition: none; } } /* --------------------------------------------------------------------------- * zh-CN: no negative tracking on CJK (TASK-055, rule class 1). * The 12 title selectors above tighten Latin display type with negative * letter-spacing. CJK glyphs are full-width squares with no side bearings to * reclaim, so the same value only crushes strokes together. Measured in the * real browser (.dev/task-055-zh-harness.html): .v2-chat__title -0.5px, * .v2-pods__title -0.32px, .v2-inspector__now-title -0.15px on Chinese text. * `html[lang]` is set by frontend/src/i18n/index.ts, so :lang(zh) matches * zh-CN. Guarded by v2-layout-invariants.test.ts. * ------------------------------------------------------------------------ */ .v2-root:lang(zh) .v2-rail__brand, .v2-root:lang(zh) .v2-board__detail .v2-modal__title, .v2-root:lang(zh) .v2-tools__title, .v2-root:lang(zh) .v2-tools__count strong, .v2-root:lang(zh) .v2-artifacts__title, .v2-root:lang(zh) .v2-team__title, .v2-root:lang(zh) .v2-team-card__name, .v2-root:lang(zh) .v2-team__empty-title, .v2-root:lang(zh) .v2-pods__title, .v2-root:lang(zh) .v2-pods__page-title, .v2-root:lang(zh) .v2-chat__title, .v2-root:lang(zh) .v2-thread__title h1, .v2-root:lang(zh) .v2-first-run__title, .v2-root:lang(zh) .v2-chat__new-pod-title, .v2-root:lang(zh) button.v2-inspector__tab, .v2-root:lang(zh) .v2-inspector__now-title, .v2-root:lang(zh) .v2-inspector__detail-name, .v2-root:lang(zh) .v2-login__title, .v2-root:lang(zh) .v2-feature__title, .v2-root:lang(zh) .v2-settings__title, .v2-root:lang(zh) .v2-settings__label, .v2-root:lang(zh) .v2-settings__account-name, .v2-root:lang(zh) .v2-settings__section .v2-billing__title, .v2-root:lang(zh) .v2-settings__section .v2-devices h2, .v2-root:lang(zh) .v2-connectors__header h1, .v2-root:lang(zh) .v2-connector-row__name, .v2-root:lang(zh) .v2-connector-aside__card h2, .v2-root:lang(zh) .v2-feature__legacy .MuiTypography-h1, .v2-root:lang(zh) .v2-feature__legacy .MuiTypography-h2, .v2-root:lang(zh) .v2-feature__legacy .MuiTypography-h3, .v2-root:lang(zh) .v2-feature__legacy .MuiTypography-h4, .v2-root:lang(zh) .v2-feature__legacy .MuiTypography-h5, .v2-root:lang(zh) .v2-feature__legacy .MuiTypography-h6, .v2-root:lang(zh) .v2-activity__title, .v2-root:lang(zh) .v2-activity__section h2, .v2-root:lang(zh) .v2-activity__agent-card h3, .v2-root:lang(zh) .v2-activity__board-row h3, .v2-root:lang(zh) .v2-byo__mode-title, .v2-root:lang(zh) .v2-byo__preview-name, .v2-root:lang(zh) .v2-byo__stat-value, .v2-root:lang(zh) .v2-connect__lane h2 { letter-spacing: 0; } /* --------------------------------------------------------------------------- * zh-CN: mono labels drop `text-transform: lowercase` (TASK-164, rule class 3). * `.v2-connector-gates__title` and `.v2-tools__field > span:first-child` set * lowercase for Latin kickers. The zh copy for both is CJK plus one Latin * token — `Pod`, the product noun, which is never a synonym — * and CSS lowercases it to `pod`, so a label contradicts the sentence beside * it. Case is not a property of CJK; the reset exists only for the Latin token * the copy carries. Guarded by v2-layout-invariants.test.ts. * ------------------------------------------------------------------------ */ .v2-root:lang(zh) .v2-connector-gates__title, .v2-root:lang(zh) .v2-tools__field > span:first-child, .v2-root:lang(zh) .v2-tools__field > legend { text-transform: none; } /* --------------------------------------------------------------------------- * zh-CN: CJK body line-height 1.6 and a 12px floor (TASK-055, rule class 2). * Latin body copy sits at 1.45–1.55 here; CJK glyphs fill the em box, so the * same leading leaves no white between lines. Measured in the real browser * (.dev/task-055-zh-harness.html): .v2-msg__content 21.7px/14px = 1.55, * .v2-chat__composer-hint 1.45, .v2-inspector__pod-meta 1.45, and the * composer hint (11px) / inspector tab (11.5px) render CJK below the 12px * legibility floor. Single-line nowrap+ellipsis rows are not touched — their * height is not text-driven. Guarded by v2-layout-invariants.test.ts. * ------------------------------------------------------------------------ */ .v2-root:lang(zh) .v2-msg__content, .v2-root:lang(zh) .v2-msg__content pre, .v2-root:lang(zh) .v2-chat__composer-hint, .v2-root:lang(zh) .v2-chat__delivery-hint, .v2-root:lang(zh) .v2-chat__readonly-text, .v2-root:lang(zh) .v2-chat__new-pod-text, .v2-root:lang(zh) .v2-first-run__lede, .v2-root:lang(zh) .v2-first-run__step-body, .v2-root:lang(zh) .v2-pods__join-notice, .v2-root:lang(zh) .v2-pods__discover-description, .v2-root:lang(zh) .v2-pods__community-copy, .v2-root:lang(zh) .v2-activity__queue-copy p, .v2-root:lang(zh) .v2-activity__queue-detail, .v2-root:lang(zh) .v2-activity__board-row p, .v2-root:lang(zh) .v2-activity__agent-recap, .v2-root:lang(zh) .v2-activity__empty, .v2-root:lang(zh) .v2-activity__footer, .v2-root:lang(zh) .v2-inspector__pod-meta, .v2-root:lang(zh) .v2-inspector__now-meta, .v2-root:lang(zh) .v2-inspector__goal-text, .v2-root:lang(zh) .v2-inspector__empty, .v2-root:lang(zh) .v2-inspector__danger-text, .v2-root:lang(zh) .v2-inspector__detail-body, .v2-root:lang(zh) .v2-modal__hint, .v2-root:lang(zh) .v2-invite-card__description, .v2-root:lang(zh) .v2-login__field-hint, .v2-root:lang(zh) .v2-billing__note, .v2-root:lang(zh) .v2-approval__summary, .v2-root:lang(zh) .v2-approval__action { line-height: 1.6; } .v2-root:lang(zh) .v2-chat__composer-hint, .v2-root:lang(zh) button.v2-inspector__tab { font-size: 12px; } /* ── Connectors — Signal Coverage artboard ──────────────────────────────── */ .v2-connectors { display: flex; flex-direction: column; gap: 28px; } .v2-connectors__header h1 { margin: 0; color: var(--v2-ink); font-family: var(--v2-font-display); font-size: 32px; font-weight: 800; letter-spacing: -0.03em; line-height: 36px; } .v2-connectors__loading { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 12px; } .v2-connectors__content { display: grid; grid-template-columns: minmax(min-content, 1fr) minmax(240px, 400px); gap: 40px; align-items: start; } .v2-connectors__main { display: flex; min-width: 0; min-height: 0; flex-direction: column; } .v2-connectors__rows { overflow: hidden; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); } .v2-connectors__inactive-fold { min-width: 0; } .v2-root button.v2-connectors__inactive-toggle { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 10px 18px; border: 0; background: var(--v2-surface); color: var(--v2-text-tertiary); font: 500 12px/16px var(--v2-font-mono); text-align: left; cursor: pointer; } .v2-root button.v2-connectors__inactive-toggle:hover { background: var(--v2-surface-hover); } .v2-root button.v2-connectors__inactive-toggle:focus-visible { box-shadow: inset 0 0 0 2px var(--v2-accent); outline: none; } .v2-connectors__inactive-caret { width: 7px; height: 7px; border-right: 1px solid currentColor; border-bottom: 1px solid currentColor; transform: rotate(-45deg); } .v2-root button.v2-connectors__inactive-toggle[aria-expanded="true"] .v2-connectors__inactive-caret { transform: rotate(45deg); } .v2-connectors__inactive-rows > .v2-connector-row:last-child { border-bottom: 0; } /* TASK-677 slice (a), D215 artboard: channel rows render as a tile grid (auto-fill, 150px minimum, per the 2026-10-31 ruling; the aside stays). Layout only: the same rows, the same act and the same connect flow. Tools rows are not tiled in this slice. The inactive fold spans the grid, and its own rows reuse the same tile template. */ .v2-connectors__rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; overflow: visible; border: 0; border-radius: 0; } .v2-connectors__rows .v2-connector-row { grid-template-columns: minmax(0, 1fr); align-content: center; min-height: 128px; border: 1px solid var(--v2-border-soft); border-radius: 14px; padding: 14px 12px; } .v2-connectors__inactive-fold { grid-column: 1 / -1; } .v2-connectors__inactive-rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; padding: 12px 0 0; } /* Lumen's 1440 HOLD (review 5722362448): the row's own two-track grid and its spanning placements sized the name, detail and act past a 150px tile. Inside a tile the content stacks in one track and wraps within the tile. */ .v2-root .v2-connectors__rows button.v2-connector-row__selection { grid-column: 1; grid-template-columns: minmax(0, 1fr); row-gap: 6px; } .v2-connectors__rows .v2-connector-row__name { min-width: 0; overflow-wrap: anywhere; flex-direction: column; align-items: center; gap: 6px; text-align: center; } .v2-connectors__rows .v2-connector-row__details { min-width: 0; overflow-wrap: anywhere; padding-right: 0; } /* The 760px rule reserved 52px beside the icon act (column 2). Inside a tile the icon act is centred under the text, so the reserve only narrowed the text. The specificity here is (0,5,1), above the 760px padding-right rule (0,4,1). */ .v2-root .v2-connectors__rows .v2-connector-row:has(.v2-connector-row__action--icon) button.v2-connector-row__selection { padding-right: 0; } .v2-root .v2-connectors__rows .v2-connector-row__action { grid-column: 1; grid-row: 2; justify-self: stretch; } /* The icon act is 32px or 44px wide, so stretch does nothing; centre it under the text. Specificity (0,4,1) beats the 760px icon placement (0,2,1). */ .v2-root .v2-connectors__rows button.v2-connector-row__action--icon { grid-column: 1; grid-row: 2; justify-self: center; } .v2-connector-row { display: grid; /* Keep columns aligned while giving details the only flexible track. The old fixed 200px + 200px + 120px tracks left details ~20px wide at 1184px, while a flexible action track let each row drift and clipped its label. */ /* Direction A (2026-09-19): the age column is gone — it rides the mono kicker above line 1 — so the row is name · details · one act. */ grid-template-columns: 140px minmax(150px, 1fr) 120px; /* TASK-162 (2): the channel name and its details met at 0px — the 140px name track ends exactly where the details track begins, so a name that fills its track touches the sentence. A 12px gutter on BOTH row grids (here and the selection button's inner grid below) keeps the two columns apart. */ column-gap: 12px; align-items: center; min-height: 82px; padding: 16px 18px; border-bottom: 1px solid var(--v2-border-soft); background: var(--v2-surface); } .v2-connector-row:last-child { border-bottom: none; } .v2-connector-row--selected { background: var(--v2-surface-tint); } .v2-connector-row--not-yet { color: var(--v2-text-tertiary); } .v2-root button.v2-connector-row__selection { display: grid; grid-column: 1 / 3; grid-template-columns: 140px minmax(150px, 1fr); column-gap: 12px; align-items: center; min-width: 0; padding: 0; border: none; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; } .v2-connector-row__name { display: inline-flex; align-items: center; gap: 10px; color: var(--v2-ink); font-family: var(--v2-font-display); font-size: 18px; font-weight: 800; letter-spacing: -0.02em; } .v2-connector-row--not-yet .v2-connector-row__name { color: var(--v2-text-tertiary); } .v2-connector-row__dot { width: 8px; height: 8px; flex: none; border-radius: var(--v2-radius-sm); background: var(--v2-border-soft); } .v2-connector-row__glyph { display: inline-flex; width: 20px; height: 20px; flex: 0 0 20px; color: inherit; } .v2-connector-row__glyph svg { width: 20px; height: 20px; } .v2-connector-row--not-yet .v2-connector-row__glyph { color: var(--v2-text-placeholder); } /* Direction A: the state dot is a mark — ink filled, hollow, dashed, grey — never cobalt (cobalt is who asks) and never a status colour (ux-lead 70159). */ .v2-connector-row__dot--live { background: var(--v2-ink); } .v2-connector-row__dot--pending { border: 1px solid var(--v2-border-strong); background: transparent; } .v2-connector-row--dead .v2-connector-row__dot, .v2-connector-row__dot--dead { background: var(--v2-text-placeholder); } .v2-connector-row__dot--empty { border: 1px solid var(--v2-border-strong); background: transparent; } .v2-connector-row__dot--idle { background: var(--v2-border-soft); } .v2-connector-row__dot--not-yet { border: 1px dashed var(--v2-border-strong); background: transparent; } .v2-connector-row__dot--pulse { animation: v2-connector-pulse 1.6s ease-in-out infinite; } @keyframes v2-connector-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(16, 24, 40, 0); } 50% { box-shadow: 0 0 0 5px rgba(16, 24, 40, 0.14); } } @media (prefers-reduced-motion: reduce) { .v2-connector-row__dot--pulse { animation: none; } } .v2-connector-row__details { display: flex; min-width: 0; padding-right: 8px; flex-direction: column; gap: 2px; color: var(--v2-text-secondary); font-size: 13px; line-height: 18px; } /* Line 1 wraps like meta does; a sentence never ellipsises at 390. */ .v2-connector-row__details strong { color: var(--v2-ink); font-size: 14px; font-weight: 600; overflow-wrap: anywhere; } .v2-connector-row__detail, .v2-connector-row__when { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 12px; line-height: 16px; } /* Meta wraps to a second line; it never ellipsises. */ .v2-connector-row__detail { overflow-wrap: anywhere; } /* TASK-162 (3): line 3 used to be the bare 16px mark, its consequence words reachable only through the glyph's tooltip — and at ≤760 the mark is hidden, so line 3 disappeared entirely on a phone. The consequence is now TEXT beside the mark; the mode word moved onto the mark itself (title + aria-label), and the glyph follows #1782 — it takes the Tools glyph's rule below for layout and colour (gap 6, tertiary, vertical-align -2px) rather than a rule of its own. That rule carries NO dimensions: the 14px is `size={14}` on the call site, held equal to the Tools glyph's own hardcoded 14 (V2ConnectorTools' local `G`) by a same-size pin in V2ConnectorsPage.test.tsx (TASK-177). 16px would grow the line box to 18px beside a 12/16 mono sentence, which is why it is 14 and not the glyph's 16 default. */ /* TASK-162 (2): the not-yet row lists two channels. Above 760 they stack in the 140px name track; at ≤760 they join with ' · ' (the separator is the only element that switches, so nothing here depends on generated content). */ .v2-connector-row__names { display: flex; flex-direction: column; } .v2-connector-row__name-sep { display: none; } .v2-connector-row__when { padding-right: 16px; } /* Direction A rule 3: `pod · verb age` in mono 11 above line 1, on every row. */ .v2-connector-row__kicker { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 11px; font-weight: 500; line-height: 16px; text-transform: lowercase; overflow-wrap: anywhere; } /* The mode word rides the kicker only where the glyph's tooltip cannot (≤760). */ .v2-connector-row__kicker-mode { display: none; } /* Direction A rule 1 (as revised by TASK-162): a category on the row is a mark, the sentence in title + aria-label — and the mark shares the Tools glyph's rule (search `.v2-connector-row__mark, .v2-tools__mode`) for layout and colour. That sharing does NOT carry the size: the two agree at 14px through two independent literals in two files, so a same-size pin in V2ConnectorsPage.test.tsx is what keeps them from drifting (TASK-177). */ .v2-root button.v2-connector-row__action, .v2-root a.v2-connector-row__action { justify-self: end; min-height: 32px; padding: 6px 12px; border: 1px solid var(--v2-ink); border-radius: var(--v2-radius-sm); background: var(--v2-ink); color: var(--v2-on-ink); font: 600 13px/18px var(--v2-font); text-decoration: none; cursor: pointer; } /* TASK-162 (1): a hovered secondary action turned INK behind an ink glyph — `.v2-root button....__action:hover:not(:disabled)` (0,4,1) outranks the `--secondary:hover` tint (0,3,1), so the gear read as a solid black square with an invisible glyph. Excluding secondary from the ink rule fixes it WITHOUT relying on source order: raising the tint's specificity would work only until someone moves a rule, and the `.v2-root` prefix that every selector here carries makes order-fragile fixes easy to write by accident. */ .v2-root button.v2-connector-row__action:hover:not(:disabled):not(.v2-connector-row__action--secondary), .v2-root a.v2-connector-row__action:hover:not(.v2-connector-row__action--secondary) { background: var(--v2-ink-hover); } .v2-root button.v2-connector-row__action:disabled { cursor: progress; opacity: 0.65; } .v2-root button.v2-connector-row__action--secondary, .v2-root a.v2-connector-row__action--secondary { border-color: var(--v2-border); background: var(--v2-surface); color: var(--v2-ink); } .v2-root button.v2-connector-row__action--secondary:hover, .v2-root a.v2-connector-row__action--secondary:hover { background: var(--v2-surface-tint); } /* Direction A rule 2: a housekeeping act (Manage) is a 32px square glyph button; the word lives in title + aria-label. 44px under 760 for the thumb. */ .v2-root button.v2-connector-row__action--icon { display: inline-grid; place-items: center; width: 32px; min-height: 32px; padding: 0; } .v2-root button.v2-connector-row__action--icon svg { width: 16px; height: 16px; } /* TASK-140: the Revoke ✕ is a SQUARE. It carries `--secondary` too, whose `min-height: 36px` (below) applies at lower specificity, and min-height beats height — so setting `height: 32px` alone measured 32×36 (ux-lead's gate on #1799, computed style). The composed selector must therefore override the MINIMUM, not just the height. Keep both: the height is the intent, the min-height is what actually releases the 36px clamp. */ .v2-root button.v2-connector-aside__secondary.v2-connector-aside__icon { display: inline-grid; place-items: center; width: 32px; height: 32px; min-height: 32px; padding: 0; } .v2-root button.v2-connector-aside__icon svg { width: 16px; height: 16px; } .v2-connectors__add { margin-top: 24px; } .v2-root button.v2-connectors__connect, .v2-root button.v2-connectors__create, .v2-root button.v2-connector-aside__primary { min-height: 40px; padding: 9px 14px; border: 1px solid var(--v2-ink); border-radius: var(--v2-radius-sm); background: var(--v2-ink); color: var(--v2-on-ink); font: 600 13px/18px var(--v2-font); cursor: pointer; } .v2-root button.v2-connectors__connect:hover, .v2-root button.v2-connectors__create:hover:not(:disabled), .v2-root button.v2-connector-aside__primary:hover:not(:disabled) { background: var(--v2-ink-hover); } .v2-root button.v2-connectors__create:disabled, .v2-root button.v2-connector-aside__primary:disabled { cursor: progress; opacity: 0.65; } .v2-connectors__add > p { margin: 8px 0 0; color: var(--v2-text-tertiary); font-size: 13px; } .v2-connectors__new-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(180px, 240px) auto; gap: 10px; margin-top: 16px; } .v2-connectors__new-row--aside { grid-template-columns: minmax(0, 1fr) auto; } .v2-connectors__new-row--aside .v2-connectors__select { grid-column: 1 / -1; } .v2-connectors__empty-pods { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 12px; } .v2-connectors__empty-pods p { margin: 0; color: var(--v2-text-secondary); font-size: 13px; line-height: 18px; } .v2-connectors__empty-pods > .v2-connectors__create { flex: 0 0 auto; } .v2-connectors__providers { display: inline-flex; overflow: hidden; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); } .v2-root button.v2-connectors__provider { min-height: 38px; padding: 7px 12px; border: none; border-right: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-secondary); font: 600 13px/18px var(--v2-font); cursor: pointer; } .v2-root button.v2-connectors__provider:last-child { border-right: none; } .v2-root button.v2-connectors__provider--selected { background: var(--v2-surface-tint); color: var(--v2-ink); } .v2-connectors__select { min-width: 0; min-height: 40px; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-ink); font: 500 13px var(--v2-font); } .v2-connectors__aside { display: flex; min-width: 0; flex-direction: column; gap: 16px; } .v2-connector-aside__step, .v2-connector-aside__card { padding: 18px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-md); background: var(--v2-panel, var(--v2-bg-subtle)); } .v2-connector-aside__step p, .v2-connector-aside__card p { margin: 0; color: var(--v2-text-secondary); font-size: 13px; line-height: 20px; } .v2-connector-aside__eyebrow { margin-bottom: 8px !important; color: var(--v2-accent-text) !important; font-family: var(--v2-font-mono); font-size: 11px !important; font-weight: 500; text-transform: lowercase; } .v2-connector-aside__card h2 { margin: 0 0 8px; color: var(--v2-ink); font-family: var(--v2-font-display); font-size: 16px; font-weight: 800; letter-spacing: -0.02em; } .v2-connector-aside__actions, .v2-connector-aside__controls { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 14px; } .v2-root button.v2-connector-aside__secondary { min-height: 36px; padding: 7px 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-ink); font: 600 13px/18px var(--v2-font); cursor: pointer; } .v2-root button.v2-connector-aside__secondary:hover { background: var(--v2-surface-tint); } .v2-connector-aside__card > .v2-connector-aside__secondary, .v2-connector-aside__card > .v2-connector-aside__primary { margin-top: 18px; } .v2-connector-aside__relay { display: inline-flex; align-items: center; gap: 7px; color: var(--v2-text-secondary); font-size: 13px; cursor: pointer; } .v2-connector-aside__relay input { accent-color: var(--v2-ink); } .v2-connector-aside__mode { display: inline-flex; overflow: hidden; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); } .v2-root button.v2-connector-aside__mode-opt { min-height: 30px; padding: 4px 10px; border: none; border-right: 1px solid var(--v2-border); background: var(--v2-surface); color: var(--v2-text-secondary); font: 600 12px/16px var(--v2-font); cursor: pointer; } .v2-root button.v2-connector-aside__mode-opt:last-child { border-right: none; } .v2-root button.v2-connector-aside__mode-opt--on { background: var(--v2-surface-tint); color: var(--v2-ink); cursor: default; } .v2-connector-code { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: center; margin-top: 14px; padding: 12px; border-radius: var(--v2-radius-sm); background: var(--v2-ink); } .v2-connector-code code { overflow-wrap: anywhere; color: var(--v2-on-ink); font-family: var(--v2-font-mono); font-size: 14px; line-height: 20px; } .v2-root button.v2-connector-code__copy { min-height: 30px; padding: 5px 9px; border: 1px solid var(--v2-accent); border-radius: var(--v2-radius-sm); background: var(--v2-accent); color: var(--v2-on-ink); font: 600 12px/16px var(--v2-font); cursor: pointer; } .v2-connector-row__refusal { grid-column: 1 / -1; margin: 10px 0 0; padding: 8px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface-tint); color: var(--v2-ink); font-size: 13px; line-height: 18px; overflow-wrap: anywhere; } .v2-connector-row__refusal a, .v2-connector-aside__refusal a { color: var(--v2-accent-text); text-decoration: underline; } .v2-connectors__error { padding: 10px 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); color: var(--v2-ink); font-size: 13px; } .v2-connector-aside__note { margin-top: 12px !important; color: var(--v2-text-tertiary) !important; font-size: 12px !important; } /* Row C: the refusal the row's own button earned, beside that button in the aside (and on the row itself) — same bordered grammar as the page slot. */ .v2-connector-aside__refusal { margin-top: 10px !important; padding: 8px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface-tint); color: var(--v2-ink); font-size: 13px; line-height: 18px; overflow-wrap: anywhere; } /* D4 gate list: one row per pod the user is in. The switch is the gate (pod → me); the active tag marks where typed messages land (me → pod). */ .v2-connector-gates { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--v2-border-soft); } .v2-connector-gates__title { margin: 0 0 6px !important; color: var(--v2-text-tertiary) !important; font-family: var(--v2-font-mono); font-size: 11px !important; line-height: 16px !important; text-transform: lowercase; } .v2-connector-gates__empty { color: var(--v2-text-tertiary) !important; font-size: 12px !important; } .v2-connector-gate { border-bottom: 1px solid var(--v2-border-soft); } .v2-connector-gate:last-child { border-bottom: none; } .v2-connector-gate__row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 10px; min-height: 36px; } .v2-root button.v2-connector-gate__name { display: inline-flex; align-items: center; gap: 8px; min-width: 0; padding: 6px 0; border: none; background: transparent; color: var(--v2-ink); font: 500 13px/18px var(--v2-font); text-align: left; cursor: pointer; } .v2-connector-gate__mark { width: 4px; height: 4px; flex: none; background: var(--v2-ink); } /* A long pod name wraps under the mark; it never ellipsises. */ .v2-connector-gate__pod { min-width: 0; overflow-wrap: anywhere; } .v2-connector-gate__tag { flex: none; color: var(--v2-ink); font-family: var(--v2-font-mono); font-size: 11px; line-height: 16px; } .v2-connector-gate__since { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 11px; line-height: 16px; white-space: nowrap; } .v2-connector-gate__since--off { color: var(--v2-text-placeholder); } /* The gate switch is the system's checkbox — the bordered square the Relay line already uses, ink when on. No pill: the system has hard edges only. */ .v2-connector-gate__switch { width: 16px; height: 16px; margin: 0; accent-color: var(--v2-ink); cursor: pointer; } .v2-connector-gate__switch:disabled { cursor: progress; opacity: 0.65; } .v2-connector-gate__more { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 4px 0 12px 12px; } .v2-connector-gate__lead { min-height: 30px; padding: 0 8px; font-size: 12px; } /* Tools — the second list (tools plan §6). Rows reuse .v2-connector-row; the aside reuses the connector aside cards. Outcomes are words in muted mono, never a coloured word. A list card is as tall as its rows (TASK-156): neither list stretches, so the page scrolls instead of a card holding empty space. */ .v2-tools__head { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 12px; } .v2-tools__title { margin: 0; color: var(--v2-ink); font-family: var(--v2-font-display); font-size: 20px; font-weight: 800; letter-spacing: -0.02em; } .v2-tools__count-line { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 12px; line-height: 16px; } .v2-tools__search { min-width: 0; flex: 1 1 200px; min-height: 32px; margin-left: auto; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-ink); font: 500 13px var(--v2-font); } .v2-tools__search:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 0; } .v2-tools__segment { flex: none; } .v2-tools__empty { margin: 0; padding: 14px 16px; color: var(--v2-text-tertiary); font-size: 13px; } .v2-tools__facts { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px; margin: 14px 0 0; } .v2-tools__facts dt { margin-top: 8px; color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 11px; line-height: 16px; text-transform: lowercase; } .v2-tools__facts dt:first-child { margin-top: 0; } .v2-tools__facts dd { margin: 0; min-width: 0; color: var(--v2-ink); font-size: 13px; line-height: 18px; overflow-wrap: anywhere; } /* A tool name is one token: the chip never breaks inside it, it wraps to the next line whole. */ .v2-tools__facts dd code { display: inline-block; margin: 0 6px 4px 0; padding: 1px 6px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); font-family: var(--v2-font-mono); font-size: 12px; overflow-wrap: normal; white-space: nowrap; } .v2-tools__counts { display: flex; flex-wrap: wrap; gap: 24px; margin-bottom: 12px; } .v2-tools__count { display: flex; flex-direction: column; gap: 2px; } .v2-tools__count strong { color: var(--v2-ink); font-family: var(--v2-font-display); font-size: 22px; font-weight: 800; letter-spacing: -0.02em; line-height: 26px; } .v2-tools__count span { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 11px; line-height: 16px; text-transform: lowercase; } .v2-tools__trail { margin: 0; padding: 0; list-style: none; } .v2-tools__trail-line { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-top: 1px solid var(--v2-border-soft); color: var(--v2-text-muted); font-family: var(--v2-font-mono); font-size: 12px; line-height: 16px; } .v2-tools__trail-line > span:first-child { min-width: 0; overflow-wrap: anywhere; } .v2-tools__trail-when { flex: none; } .v2-tools__mode, .v2-tools__outcome, .v2-connector-row__mark { display: inline-flex; align-items: center; margin-right: 6px; vertical-align: -2px; color: var(--v2-text-tertiary); } .v2-tools__form { display: grid; gap: 14px; margin-top: 14px; } .v2-tools__field { display: grid; gap: 6px; margin: 0; padding: 0; border: none; min-width: 0; } .v2-tools__field > span:first-child, .v2-tools__field > legend { color: var(--v2-text-tertiary); font-family: var(--v2-font-mono); font-size: 11px; line-height: 16px; text-transform: lowercase; padding: 0; } .v2-tools__input { min-width: 0; min-height: 40px; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-ink); font: 500 13px var(--v2-font); } .v2-tools__input:focus-visible { outline: 2px solid var(--v2-accent); outline-offset: 0; } .v2-tools__agents { display: grid; gap: 6px; } .v2-tools__hint { color: var(--v2-text-secondary); font-size: 12px; line-height: 18px; } .v2-tools__hint code { display: inline-block; margin: 0 6px 4px 0; padding: 1px 6px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); font-family: var(--v2-font-mono); font-size: 12px; white-space: nowrap; } @media (max-width: 1010px) { .v2-connectors__content { grid-template-columns: minmax(0, 1fr); gap: 24px; } } @media (max-width: 760px) { .v2-connectors { gap: 24px; margin: -12px -18px 0; } .v2-connectors__content { grid-template-columns: minmax(0, 1fr); gap: 24px; } .v2-connector-row { grid-template-columns: minmax(0, 1fr) auto; min-height: 0; padding: 14px 12px; } .v2-root button.v2-connector-row__selection { grid-column: 1 / -1; grid-template-columns: minmax(0, 1fr) auto; row-gap: 4px; } .v2-root button.v2-connector-row__selection .v2-connector-row__name { grid-column: 1; grid-row: 1; } .v2-root button.v2-connector-row__selection .v2-connector-row__details { grid-column: 1 / -1; grid-row: 2; } .v2-root button.v2-connector-row__selection .v2-connector-row__when { grid-column: 1 / -1; grid-row: 3; padding-right: 0; } .v2-connector-row--not-yet .v2-connector-row__name { grid-column: 1; grid-row: 1; } .v2-connector-row--not-yet .v2-connector-row__details { grid-column: 1 / -1; grid-row: 2; } .v2-connector-row--not-yet .v2-connector-row__when { grid-column: 1 / -1; grid-row: 3; padding-right: 0; } /* A phone keeps the row's REASON. This used to be a blanket hide with enumerated exceptions (`:not(.v2-connector-row--dead):not(.v2-connector-row--not-enabled)`), which silently swallowed every state the list had not anticipated: the not-yet row that IS available (V2ConnectorTools.tsx:562) lost "install the GitHub App first" / "read, or read and write", and a stranger saw a "not granted" kicker with no reason under it (eng lead 73726). Default is now SHOW; if one row ever needs its detail hidden on phones, hide that named case here rather than re-introducing an exception list. */ .v2-root button.v2-connector-row__action, .v2-root a.v2-connector-row__action { grid-column: 2; grid-row: 1; z-index: 1; } /* Direction A at 390 (after the rule above so it wins): no tooltips, so the mode word rides the kicker; the gear is 44px in row 1 beside the name; a row's word act is full width under the sentence; rows keep one height. */ .v2-connector-row { min-height: 72px; } .v2-root button.v2-connector-row__selection { grid-row: 1; } .v2-connector-row__kicker-mode { display: inline; } .v2-connector-row__mark { display: none; } .v2-connector-row__names { display: block; } .v2-connector-row__name-sep { display: inline; } .v2-root button.v2-connector-row__action--icon { width: 44px; min-height: 44px; grid-column: 2; grid-row: 1; justify-self: end; align-self: start; } .v2-root button.v2-connector-row__action:not(.v2-connector-row__action--icon), .v2-root a.v2-connector-row__action { display: inline-flex; grid-column: 1 / -1; grid-row: 3; width: 100%; justify-content: center; min-height: 44px; margin-top: 8px; } /* The gear sits over the selection button's top-right; keep the kicker out from under it. */ .v2-connector-row:has(.v2-connector-row__action--icon) .v2-root button.v2-connector-row__selection, .v2-root .v2-connector-row:has(.v2-connector-row__action--icon) button.v2-connector-row__selection { padding-right: 52px; } .v2-root button.v2-connector-aside__secondary.v2-connector-aside__icon { width: 44px; height: 44px; min-height: 44px; } .v2-connectors__new-row { grid-template-columns: minmax(0, 1fr); } .v2-connectors__providers { width: fit-content; } .v2-connector-gate__more { padding-left: 0; } .v2-tools__head { gap: 8px; } .v2-tools__search { flex-basis: 100%; margin-left: 0; } } /* Activity queue: reply-in-place on mention rows (2026-09-01). The textarea shares the row's action cluster; on narrow screens it takes the full width of the row so the thumb has something to hit. */ .v2-activity__reply { display: flex; align-items: center; gap: 6px; flex: 1 1 260px; min-width: 0; } .v2-root .v2-activity__reply button { flex: 0 0 auto; min-width: max-content; min-height: 32px; padding: 0 12px; white-space: nowrap; } .v2-root textarea.v2-activity__reply-input { flex: 1 1 auto; min-width: 0; height: 32px; min-height: 32px; padding: 6px 10px; resize: none; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); font: inherit; font-size: 13px; line-height: 18px; } .v2-root textarea.v2-activity__reply-input:focus-visible { border-color: var(--v2-accent); /* the global halo carries the ring; no hard outline */ } @media (max-width: 640px) { .v2-activity__reply { flex-basis: 100%; } .v2-root .v2-activity__reply button { min-height: 44px; } } /* ---------- Workspace sidebar (TASK-129 PR 1) ---------- The workspace artboard is a ground-colour grid, not three inset cards. These rules intentionally follow the retired sidebar rules above while the chat and inspector receive their own structural passes in PRs 2 and 3. */ .v2-shell { gap: 14px; padding: 14px; box-sizing: border-box; } .v2-shell .v2-pane { height: 100%; min-height: 0; } .v2-shell .v2-pane--main { margin: 0; height: 100%; } .v2-pods { position: relative; height: 100%; padding: 6px 0; background: var(--v2-shell-bg); } @media (max-width: 760px) { .v2-shell, .v2-shell--no-inspector, .v2-shell--feature { gap: 0; padding: 0; } .v2-shell .v2-pane { height: 100vh; } /* A pane INSIDE the authenticated shell is bounded by the shell's content box, not by the viewport: that box has already had the verify-email banner subtracted from it, so a 100vh pane overflows below the fold by the banner's height. With its own `overflow: hidden` the pod header then sits under the banner — the back button, the title and the inspector toggle all untappable, and there is nothing to scroll (TASK-157, ux-lead at 390, ux-lead's P1). Ranked (0,3,0) against the (0,2,0) rule above so it wins on specificity, not on coming later: the same lesson as #1868, where a tie resolved by file order silently erased a component's own declarations. The 100vh rule itself stays — it is the right height outside this shell — and this guard is what keeps it from winning here. */ .v2-authenticated-shell__content .v2-shell .v2-pane { height: 100%; } .v2-pods-aside { width: min(86vw, 320px); } .v2-pods__mobile-close { position: absolute; top: 6px; right: 6px; z-index: 1; } /* The inspector is a bottom sheet on phones, not a narrow desktop drawer. */ .v2-pane--inspector { top: auto; left: 0; width: 100%; max-height: min(78dvh, 680px); border: 1px solid var(--v2-border); border-bottom: 0; border-radius: 6px 6px 0 0; box-shadow: 0 -12px 32px rgba(17, 24, 39, 0.14); } } /* ---------- Workspace inspector (TASK-129 PR 2) ---------- Three factual cards replace the old tabbed inspector. The route keeps the same invite, agent-profile, board, and attachment exits without retaining a second, legacy inspector surface. */ .v2-workspace-inspector { position: relative; display: flex; min-height: 0; height: 100%; flex-direction: column; gap: 10px; overflow-y: auto; background: var(--v2-shell-bg); } /* The new inspector is a card stack on the shell ground, not a second pane delineated by a desktop divider. Its cards provide the only borders. */ .v2-pane--inspector { border-left: 0; } .v2-workspace-inspector__card { min-width: 0; border: 0; border-radius: var(--v2-r-14, 14px); background: var(--v2-surface); box-shadow: var(--v2-shadow-pane, 0 0 0 1px var(--v2-border-soft)); padding: 12px; } .v2-workspace-inspector__label { display: block; margin: 0; color: var(--v2-text-primary); font: 600 13px/18px var(--v2-font); white-space: nowrap; } /* ---------- D215 panel fold (TASK-691) ---------- Needs you, Agents, Files and Who can join are each one 44px row at rest and open on demand. The section titles lost their mono captions; an icon and a count say the same thing. Members and manage are icon buttons in the head. */ .v2-workspace-inspector__head { display: flex; min-height: 32px; flex: none; align-items: center; justify-content: flex-end; gap: 6px; padding: 8px 10px 0; } .v2-workspace-inspector__card.v2-workspace-inspector__group { flex: none; padding: 0; overflow: hidden; } .v2-root button.v2-workspace-inspector__fold { display: flex; width: 100%; min-width: 0; height: 44px; align-items: center; gap: 9px; padding: 0 12px 0 14px; border: 0; border-radius: 0; background: transparent; color: var(--v2-text-primary); font: 600 13.5px/18px var(--v2-font); text-align: left; cursor: pointer; } .v2-root button.v2-workspace-inspector__fold:hover { background: var(--v2-surface-hover); } .v2-root button.v2-workspace-inspector__fold:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--v2-accent); } .v2-workspace-inspector__fold-icon { display: grid; flex: none; place-items: center; color: var(--v2-text-secondary); } .v2-workspace-inspector__fold-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; } .v2-workspace-inspector__fold-count { color: var(--v2-text-muted); font: 500 11.5px/1 var(--v2-font-mono); } .v2-workspace-inspector__fold-stack { display: flex; margin-left: auto; padding-left: 6px; } .v2-workspace-inspector__fold-avatar.v2-avatar { width: 24px; height: 24px; margin-left: -6px; border: 2px solid var(--v2-surface); border-radius: 6px; box-shadow: none; } .v2-workspace-inspector__fold-chevron { display: grid; flex: none; margin-left: auto; place-items: center; color: var(--v2-text-placeholder); transition: transform 160ms; } .v2-workspace-inspector__fold-stack + .v2-workspace-inspector__fold-chevron { margin-left: 0; } .v2-workspace-inspector__fold[aria-expanded="true"] .v2-workspace-inspector__fold-chevron { transform: rotate(180deg); } .v2-workspace-inspector__group-body { padding: 0 14px 12px; } .v2-workspace-inspector__group-body .v2-pod-join-settings { margin: 0; padding: 0; border: 0; } .v2-workspace-inspector__rows { display: flex; min-width: 0; flex-direction: column; gap: 4px; } .v2-root button.v2-workspace-inspector__agent, .v2-root button.v2-workspace-inspector__attention, .v2-root button.v2-workspace-inspector__task, .v2-root button.v2-workspace-inspector__board-counts { width: 100%; min-width: 0; border: 0; border-radius: 4px; background: transparent; color: var(--v2-text-primary); text-align: left; } .v2-root button.v2-workspace-inspector__agent { display: grid; grid-template-columns: 28px minmax(0, 1fr) 8px; align-items: center; gap: 8px; padding: 6px 4px; } .v2-root button.v2-workspace-inspector__agent:hover, .v2-root button.v2-workspace-inspector__attention:hover, .v2-root button.v2-workspace-inspector__task:hover, .v2-root button.v2-workspace-inspector__board-counts:hover { background: var(--v2-surface-hover); } .v2-workspace-inspector__avatar.v2-avatar { width: 28px; height: 28px; border: 0; border-radius: 4px; box-shadow: none; font-size: 12px; } .v2-workspace-inspector__agent-copy { display: flex; min-width: 0; flex-direction: column; gap: 1px; } .v2-workspace-inspector__agent-name { overflow: hidden; color: var(--v2-text-primary); font: 600 13px/18px var(--v2-font); text-overflow: ellipsis; white-space: nowrap; } .v2-workspace-inspector__agent-status { overflow: hidden; color: var(--v2-text-muted); font: 400 12px/16px var(--v2-font); text-overflow: ellipsis; white-space: nowrap; } .v2-workspace-inspector__state { width: 8px; height: 8px; border-radius: 0; background: var(--v2-text-muted); } .v2-workspace-inspector__state--needs-you { background: var(--v2-accent); } .v2-workspace-inspector__state--working { background: var(--v2-accent); animation: v2-pulse var(--motion-pulse) var(--motion-ease-state) infinite; } .v2-root button.v2-workspace-inspector__attention, .v2-root button.v2-workspace-inspector__task { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 7px 4px; font: 400 13px/18px var(--v2-font); } .v2-workspace-inspector__attention > span:first-child, .v2-workspace-inspector__task > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-workspace-inspector__actor, .v2-workspace-inspector__task-meta { flex-shrink: 0; color: var(--v2-accent-text); font: 500 11px/14px var(--v2-font-mono); } .v2-workspace-inspector__task-meta { color: var(--v2-text-muted); } .v2-root button.v2-workspace-inspector__board-counts { margin: 0 0 6px; padding: 0 4px 7px; border-bottom: 1px solid var(--v2-border-soft); color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); } .v2-workspace-inspector__empty { margin: 0; padding: 4px; color: var(--v2-text-muted); font: 400 12px/16px var(--v2-font); } .v2-root button.v2-workspace-inspector__close { display: none; width: 28px; height: 28px; place-items: center; padding: 0; border: 0; border-radius: 4px; background: transparent; color: var(--v2-text-secondary); } .v2-root button.v2-workspace-inspector__close:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-workspace-inspector__close:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } @media (max-width: 760px) { .v2-workspace-inspector { padding: 12px 14px 0; } .v2-root button.v2-workspace-inspector__close { display: inline-grid; } } /* The new factual inspector keeps CJK metadata at the established readable floor. These rows are the artboard's compact mono labels, not body prose. */ .v2-root:lang(zh) .v2-workspace-inspector__empty { line-height: 1.6; } .v2-root:lang(zh) .v2-workspace-inspector__actor, .v2-root:lang(zh) .v2-workspace-inspector__task-meta { font-size: 12px; } /* ---------- Workspace decision card (TASK-129 PR 3) ---------- A DecisionRequest is an in-thread fork, not prose the human must parse. The cobalt 2px ring is reserved for this unresolved, human-owned choice. */ .v2-decision-card { display: flex; flex-direction: column; gap: 10px; margin: 8px 0; padding: 14px; border: 1px solid var(--v2-border-soft); border-radius: 6px; background: var(--v2-surface); box-shadow: 0 0 0 2px var(--v2-accent); } .v2-decision-card--ruled { box-shadow: none; } .v2-decision-card__head { display: flex; align-items: baseline; gap: 8px; min-width: 0; } .v2-decision-card__head h3 { min-width: 0; margin: 0; color: var(--v2-text-primary); font: 600 14px/20px var(--v2-font); } .v2-decision-card__agent { flex-shrink: 0; color: var(--v2-accent-text); font: 500 11px/14px var(--v2-font-mono); } .v2-decision-card__question { margin: 0; color: var(--v2-text-secondary); font: 400 13px/19px var(--v2-font); } .v2-decision-card__options { display: grid; gap: 12px; } .v2-decision-card__option { display: grid; min-width: 0; gap: 4px; } .v2-root button.v2-decision-card__choice, .v2-root button.v2-decision-card__other, .v2-root button.v2-decision-card__other-form button { min-height: 32px; padding: 6px 10px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-primary); font: 600 13px/20px var(--v2-font); } .v2-root button.v2-decision-card__choice { width: 100%; justify-content: flex-start; text-align: left; white-space: normal; } .v2-root button.v2-decision-card__choice--primary { border-color: var(--v2-accent); background: var(--v2-accent); color: var(--v2-on-ink); } .v2-root button.v2-decision-card__choice:hover:not(:disabled), .v2-root button.v2-decision-card__other:hover:not(:disabled) { background: var(--v2-surface-hover); } .v2-root button.v2-decision-card__choice--primary:hover:not(:disabled) { background: var(--v2-accent-strong); } .v2-decision-card__option-description { color: var(--v2-text-secondary); font: 400 14px/20px var(--v2-font); } .v2-decision-card__option-recommended { color: var(--v2-text-muted); font: 500 11px/14px var(--v2-font-mono); } .v2-root button.v2-decision-card__other { border: 0; background: transparent; color: var(--v2-accent-text); } .v2-decision-card__footer { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } .v2-decision-card__other-form { display: flex; flex: 1 1 100%; gap: 6px; } .v2-decision-card__other-form input { min-width: 0; flex: 1; min-height: 32px; border: 1px solid var(--v2-border); border-radius: 4px; padding: 5px 8px; background: var(--v2-surface); color: var(--v2-text-primary); font: 400 13px/18px var(--v2-font); } .v2-decision-card__settled, .v2-decision-card__error { margin: 0; font: 500 12px/18px var(--v2-font); } .v2-decision-card__settled { color: var(--v2-text-secondary); } .v2-decision-card__error { color: #b91c1c; } .v2-msg__ruled { color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); } /* ---------- Workspace thread and composer (TASK-129 PR 3) ---------- */ .v2-thread__header { flex: 0 0 auto; box-sizing: border-box; min-height: 50px; padding: 0 14px; border-bottom: 1px solid var(--v2-border-soft); background: var(--v2-surface); } .v2-thread__header-row { display: flex; align-items: center; gap: 10px; min-width: 0; } .v2-thread__title { min-width: 0; flex: 1; } .v2-thread__title-line { display: flex; align-items: baseline; min-width: 0; gap: 8px; } .v2-thread__title h1 { margin: 0; overflow: hidden; color: var(--v2-text-primary); /* Direction C (walk-1 ruling b): a pod is a conversation, not a page — sans 15/600 replaces the display face here; Bricolage stays on page titles. */ font: 600 15px/20px var(--v2-font); letter-spacing: 0; text-overflow: ellipsis; white-space: nowrap; /* The description gives way before the name truncates (walk-1 §3). */ flex: 0 1 auto; min-width: 0; max-width: 100%; } .v2-root button.v2-thread__inspector-toggle { display: inline-grid; width: 28px; height: 28px; flex: 0 0 28px; padding: 0; place-items: center; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-secondary); } .v2-root button.v2-thread__inspector-toggle:hover, .v2-root button.v2-thread__inspector-toggle--active { background: var(--v2-surface-hover); color: var(--v2-text-primary); } /* TASK-702: the header Invite. Same height and frame as the inspector toggle beside it, with a label so it reads as an action, not decoration. */ .v2-root button.v2-pod-header__invite { display: inline-flex; height: 28px; flex: 0 0 auto; align-items: center; gap: 6px; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-primary); font: inherit; font-size: 13px; white-space: nowrap; cursor: pointer; } .v2-root button.v2-pod-header__invite:hover { background: var(--v2-surface-hover); } /* On a phone the label would take the pod name's width, so the button keeps only its glyph, square like the inspector toggle. The label stays in the accessibility tree as the button's name. */ @media (max-width: 760px) { .v2-root button.v2-pod-header__invite { width: 28px; flex: 0 0 28px; justify-content: center; padding: 0; } .v2-root button.v2-pod-header__invite span { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; border: 0; } } .v2-thread .v2-msg { grid-template-columns: 28px minmax(0, 1fr); gap: 8px; padding: 8px 0; } .v2-thread .v2-msg--grouped { padding: 2px 0; } .v2-thread .v2-msg__avatar-ghost { width: 28px; } .v2-thread .v2-avatar { width: 28px; height: 28px; border: 0; border-radius: 4px; box-shadow: none; } .v2-thread .v2-msg__head { height: 18px; gap: 6px; } .v2-thread .v2-msg__author, .v2-thread .v2-msg__author-btn { font-size: 14px; font-weight: 600; } .v2-thread .v2-msg__time { font: 500 12px/16px var(--v2-font-mono); } .v2-thread .v2-msg__avatar-btn { border-radius: 4px; } .v2-thread .v2-msg__actions { border-radius: 4px; box-shadow: none; } .v2-message-row--decision { padding: 8px 0; } .v2-composer__error { margin: 0; padding: 0 10px 8px; color: #b91c1c; font: 400 12px/16px var(--v2-font); } .v2-composer__warnings { display: flex; flex-direction: column; gap: 4px; padding: 0 10px 8px; color: var(--v2-text-secondary); font: 400 12px/16px var(--v2-font); } @media (max-width: 760px) { .v2-thread__header { min-height: 50px; padding: 0 12px; } .v2-thread__header-row { align-items: center; gap: 8px; } .v2-thread__title-line { display: flex; flex-wrap: wrap; align-items: center; } /* The name takes the free width with a zero basis and truncates, so the "i" hint keeps its place on the line instead of wrapping under it and growing the header (TASK-647 item 3). */ .v2-thread__title h1 { font: 600 15px/20px var(--v2-font); flex: 1 1 0; min-width: 0; white-space: nowrap; text-overflow: ellipsis; } .v2-thread .v2-msg__author, .v2-thread .v2-msg__author-btn { font-size: 15px; } .v2-thread .v2-msg__time, .v2-thread .v2-msg__ruled { font-size: 12px; } .v2-thread .v2-msg__content { font-size: 15px; line-height: 22px; } /* The phone artboard makes every decision option a full-width, 44px row; Other remains a centred text escape hatch beneath them. */ .v2-decision-card__options { align-items: stretch; flex-direction: column; } .v2-decision-card__option { width: 100%; } .v2-root button.v2-decision-card__choice { width: 100%; min-height: 44px; font-size: 15px; } .v2-root button.v2-decision-card__other { align-self: flex-start; min-height: 44px; } /* The workspace is edge-to-edge on a phone. Rail and pod list are drawers, while the transcript, composer, and tab bar share the white canvas. */ /* The 1023px rule is more specific and otherwise leaves three tracks active at phone width. The rail is hidden below, so every shell must explicitly collapse to one main track. */ .v2-shell:not(.v2-shell--feature-wide), .v2-shell--feature-wide { grid-template-columns: minmax(0, 1fr); } .v2-shell, .v2-shell--no-inspector, .v2-shell--feature { grid-template-columns: minmax(0, 1fr); padding: 0; gap: 0; background: var(--v2-surface); } .v2-pane--rail { display: none; } .v2-pane--main { background: var(--v2-surface); } /* The inspector becomes the artboard's bottom sheet; its header toggle is intentionally always present so the sheet cannot become unreachable. */ .v2-pane--inspector { top: auto; right: 0; bottom: 0; width: 100%; height: min(76dvh, 620px); border: 1px solid var(--v2-border); border-bottom: 0; border-radius: 12px 12px 0 0; box-shadow: 0 -12px 32px rgba(17, 24, 39, 0.14); } .v2-mobile-tabs { position: fixed; right: 0; bottom: 0; left: 0; z-index: 40; display: grid; grid-template-columns: repeat(4, 1fr); height: 54px; padding: 5px 14px; border-top: 1px solid var(--v2-border); background: var(--v2-surface); } .v2-root button.v2-mobile-tabs__item { position: relative; display: grid; width: 44px; height: 32px; justify-self: center; padding: 0; place-items: center; border: 0; border-radius: 4px; background: transparent; color: var(--v2-text-secondary); } .v2-root button.v2-mobile-tabs__item svg { width: 18px; height: 18px; } .v2-root button.v2-mobile-tabs__item--active { background: var(--v2-ink); color: var(--v2-on-ink); } .v2-root button.v2-mobile-tabs__item:hover:not(:disabled) { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-mobile-tabs__item--active:hover:not(:disabled) { background: var(--v2-ink-hover); color: var(--v2-on-ink); } .v2-mobile-tabs__badge { position: absolute; top: -4px; right: -2px; display: grid; min-width: 16px; height: 16px; padding: 0 3px; place-items: center; border: 2px solid #fff; border-radius: 999px; background: var(--v2-accent); color: #fff; font: 700 11px/1 var(--v2-font-mono); } } .v2-mobile-tabs { display: none; } @media (max-width: 760px) { .v2-mobile-tabs { display: grid; } } /* ---------- Workspace at scale · direction C · PR 1 (sidebar + header + 390 list page) ---------- Ruled 2026-09-06 (walk 1): grid 56 / 260 / fluid / 272 with 14px gaps; the sidebar is a white bordered panel; Pinned, Recent (eight by my last visit), Everything folded by kind; every row carries a 22px mark, the needs-you pill and the last-message time; the pod header is 50px with a 15/600 sans title and inline meta. On the phone the pods list is a page and the drawer is gone. Nothing under 11px mono / 12px sans. */ .v2-pods-aside { background: var(--v2-shell-bg); } /* D223 (TASK-735): the artboard's .pane.pods. A 14px card on the shell ground, its edge a shadow ring rather than a border, with the rows inset. */ .v2-pods { display: flex; min-height: 0; height: 100%; flex-direction: column; padding: 12px 10px; border: 0; border-radius: var(--v2-r-14, 14px); background: var(--v2-surface); box-shadow: var(--v2-shadow-pane, 0 0 0 1px var(--v2-border-soft)); overflow: hidden; } /* The phone page is the whole screen: no card, a 52px title bar (.mtop). */ .v2-pods-aside--page .v2-pods { padding: 0; border-radius: 0; box-shadow: none; } .v2-pods__bar { display: flex; flex: none; height: 52px; align-items: center; gap: 8px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--v2-border-soft); } .v2-pods__page-title { flex: 1; min-width: 0; margin: 0; overflow: hidden; color: var(--v2-text-primary); font: 800 21px/1 var(--v2-font-display, var(--v2-font)); letter-spacing: -0.03em; text-overflow: ellipsis; white-space: nowrap; } .v2-pods-aside--page .v2-pods__body { display: flex; min-height: 0; flex: 1; flex-direction: column; padding: 12px; } .v2-pods__body { display: contents; } .v2-pods__tools { display: flex; flex: 0 0 auto; align-items: center; gap: 8px; padding: 0 2px 10px; } .v2-pods__search { display: flex; min-width: 0; flex: 1; align-items: center; gap: 7px; margin: 0; height: 34px; padding: 0 8px 0 10px; border: 0; border-radius: var(--v2-r-10, 10px); background: var(--v2-bg-subtle); box-shadow: inset 0 0 0 1px var(--v2-border-soft); color: var(--v2-text-placeholder); } .v2-pods__search > svg { flex: none; } .v2-pods__search:focus-within { border-color: var(--v2-border-strong); box-shadow: inset 0 0 0 2px var(--v2-accent); } .v2-pods__search-input { min-width: 0; flex: 1; border: 0; padding: 0; background: transparent; color: var(--v2-text-primary); font: 400 13px/18px var(--v2-font); outline: none; } .v2-pods__search-input::placeholder { color: var(--v2-text-placeholder); } .v2-pods__search-input::-webkit-search-cancel-button { -webkit-appearance: none; } .v2-pods__search-kbd { flex: 0 0 auto; padding: 3px 5px; border: 0; border-radius: 5px; background: var(--v2-surface); box-shadow: 0 0 0 1px var(--v2-border-soft); color: var(--v2-text-muted); font: 500 11px/1 var(--v2-font-mono); } @media (max-width: 760px), (hover: none) and (pointer: coarse) { .v2-pods__search-kbd { display: none; } } /* The artboard's .b.b-s.ib: a 32px raised key holding a plus glyph. */ .v2-root button.v2-pods__new { display: inline-grid; width: 32px; height: 32px; flex: 0 0 32px; padding: 0; place-items: center; border: 1px solid var(--v2-key-edge, var(--v2-border)); border-radius: var(--v2-r-8, 8px); background: linear-gradient(180deg, var(--v2-key-a, var(--v2-surface)), var(--v2-key-b, var(--v2-surface))); box-shadow: var(--v2-key-inset, none); color: var(--v2-text-primary); } .v2-root button.v2-pods__new:hover:not(:disabled), .v2-root button.v2-pods__new[aria-expanded="true"] { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-pods__new:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } /* ---------- D215 sidebar controls (TASK-691) ---------- Controls look like controls: an icon button, a chip or a segment, never grey words that click. The segment is shared by the pod list (Recent · All · Pinned), the panel's Who can join and Settings › Look. */ .v2-seg { display: inline-flex; flex: none; gap: 2px; padding: 2px; border-radius: 9px; background: var(--v2-surface-tint); box-shadow: inset 0 0 0 1px var(--v2-border-soft); } .v2-root button.v2-seg__option { display: inline-flex; height: 28px; align-items: center; gap: 6px; padding: 0 10px; border: 0; border-radius: 7px; background: transparent; color: var(--v2-text-secondary); font: 500 13px/1 var(--v2-font); white-space: nowrap; cursor: pointer; } .v2-root .v2-seg--sm button.v2-seg__option { height: 24px; padding: 0 8px; font-size: 12px; } .v2-root button.v2-seg__option:hover:not(:disabled) { color: var(--v2-text-primary); } .v2-root button.v2-seg__option--on, .v2-root button.v2-seg__option--on:hover:not(:disabled) { background: var(--v2-surface); color: var(--v2-text-primary); font-weight: 600; box-shadow: 0 0 0 1px var(--v2-border); } .v2-root button.v2-seg__option:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } .v2-root button.v2-seg__option:disabled { cursor: default; opacity: 0.55; } .v2-seg__count { color: var(--v2-text-muted); font: 500 11px/1 var(--v2-font-mono); } /* A square ghost icon button; the word lives in aria-label and title. */ .v2-root button.v2-icon-button { display: inline-grid; width: 28px; height: 28px; flex: none; place-items: center; padding: 0; border: 1px solid transparent; border-radius: 8px; background: transparent; color: var(--v2-text-secondary); cursor: pointer; } .v2-root button.v2-icon-button:hover:not(:disabled) { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-icon-button:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } .v2-pods__view { padding: 2px 2px 8px; } .v2-pods-aside--page .v2-pods__view { padding: 0 0 10px; } .v2-pods__list { display: flex; min-height: 0; flex: 1; flex-direction: column; gap: 0; padding: 0; overflow-y: auto; /* The minute poll re-reads /api/pods and the rows re-sort by lastMessage, so a message to any pod moves a row and native anchoring drags the list to keep that row's viewport offset — 4 of 17 rows stayed in view (ux-lead gate on #1989). Opting this scroller out holds 16 of 17. Unlike .v2-chat__messages, which keeps anchoring at rest for late media above the viewport, these rows are fixed-height text with no late layout to lose. */ overflow-anchor: none; } .v2-pods__section { min-width: 0; } .v2-pods__section-head, .v2-root button.v2-pods__section-head { display: flex; width: 100%; min-width: 0; align-items: center; gap: 6px; margin: 0; padding: 10px 12px 4px; border: 0; background: transparent; color: var(--v2-text-secondary); font: 600 12px/16px var(--v2-font); text-align: left; } .v2-root button.v2-pods__section-head { cursor: pointer; } .v2-root button.v2-pods__section-head:hover { color: var(--v2-text-primary); } .v2-pods__section-count { color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-pods__section-chevron { margin-left: auto; color: var(--v2-text-muted); font-size: 11px; } .v2-pods__section-chevron::before { content: '▸'; } [aria-expanded="true"] > .v2-pods__section-chevron::before { content: '▾'; } .v2-root .v2-pods__section--kind button.v2-pods__section-head { padding-left: 24px; text-transform: lowercase; } .v2-pods__rows { display: flex; flex-direction: column; gap: 2px; } /* The artboard's .pod: a 36px inset row with 8px corners. */ .v2-root button.v2-pods__row { display: grid; width: 100%; min-width: 0; min-height: 36px; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: center; gap: 9px; padding: 0 8px; border: 0; border-radius: var(--v2-r-8, 8px); background: transparent; color: var(--v2-ink-2, var(--v2-text-primary)); font: 500 13.5px/18px var(--v2-font); text-align: left; } .v2-root button.v2-pods__row--in-fold { padding-left: 24px; } /* A row and its pin control are siblings (a button cannot nest a button). */ .v2-pods__rowwrap { position: relative; } .v2-root button.v2-pods__pin { position: absolute; top: 50%; right: 6px; display: grid; width: 28px; height: 28px; place-items: center; padding: 0; transform: translateY(-50%); border: 0; border-radius: var(--v2-r-8, 8px); background: var(--v2-surface-tint); color: var(--v2-text-secondary); visibility: hidden; } /* D215: the pin is an icon on row hover that takes the time's slot. Out of sight at rest, pinned or not; the Pinned segment lists the pinned pods. visibility (not opacity) so a hidden pin cannot catch a tap. Keyboard focus anywhere in the row shows it, so Tab reaches it; a mouse click does not set :focus-visible, so a clicked row keeps its time. Touch screens have no hover, so they show the pin at rest in place of the time. */ .v2-pods__rowwrap:hover .v2-pods__pin, .v2-pods__rowwrap:has(:focus-visible) .v2-pods__pin { visibility: visible; } .v2-root button.v2-pods__pin:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } .v2-root button.v2-pods__pin--active { color: var(--v2-accent-text); } .v2-root button.v2-pods__pin:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-pods__row-time { display: inline-block; min-width: 24px; text-align: right; } .v2-pods__rowwrap:hover .v2-pods__row-time, .v2-pods__rowwrap:has(:focus-visible) .v2-pods__row-time { visibility: hidden; } @media (hover: none) and (pointer: coarse) { .v2-root button.v2-pods__pin { visibility: visible; } .v2-pods__row-time { visibility: hidden; } } .v2-root button.v2-pods__row:hover { background: var(--v2-surface-hover); } .v2-root button.v2-pods__row:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--v2-accent); } /* D223 (TASK-735): the artboard's .pod.on, in both themes. The row goes to the neutral tint and the mark alone turns cobalt; no full-row block, no accent bar. */ .v2-root button.v2-pods__row--selected, .v2-root button.v2-pods__row--selected:hover { background: var(--v2-row-active); color: var(--v2-row-active-text); font-weight: 600; } .v2-pods__row-mark { display: grid; width: 24px; height: 24px; place-items: center; border-radius: var(--v2-r-6, 6px); background: var(--v2-surface-tint); color: var(--v2-text-secondary); /* The artboard's .mk draws 600 10px mono; 11px is the mono floor (ruling h). */ font: 600 11px/1 var(--v2-font-mono); } /* A DM row carries the peer's avatar in the same 24px slot. */ .v2-pods__row-mark.v2-avatar { width: 24px; height: 24px; border-radius: var(--v2-r-6, 6px); border: 0; font-size: 11px; } .v2-root button.v2-pods__row--selected .v2-pods__row-mark:not(.v2-avatar) { background: var(--v2-row-active-mark); color: var(--v2-on-accent); } .v2-pods__row-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-root button.v2-pods__row--unread .v2-pods__row-name { font-weight: 600; } .v2-pods__row-meta { display: flex; flex: 0 0 auto; align-items: center; gap: 6px; color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); } .v2-root button.v2-pods__row--selected .v2-pods__row-meta { color: var(--v2-row-active-mute); } .v2-root button.v2-pods__row--selected:focus-visible { box-shadow: inset 0 0 0 2px var(--v2-accent); } /* The artboard's .un: an 18px ink pill, the same on the selected row. */ .v2-pods__row-pill { display: grid; min-width: 18px; height: 18px; padding: 0 5px; place-items: center; border-radius: 9px; background: var(--v2-ink); color: var(--v2-on-ink); font: 600 11px/18px var(--v2-font-mono); } /* At 760px and below the row keeps a 44px touch target. The artboard draws 36px rows at 390; its 24px mark and 13.5px name hold, the row height does not (TASK-735: a deliberate touch floor, flagged for UX Lead). */ @media (max-width: 760px) { .v2-root button.v2-pods__row { min-height: 44px; grid-template-columns: 24px minmax(0, 1fr) auto; } .v2-root button.v2-pods__pin { width: 28px; height: 28px; } } .v2-pods__create { margin: 0 10px 6px; } .v2-pods__empty { padding: 20px 12px; } .v2-pods__empty--mono { color: var(--v2-text-muted); font: 400 12px/16px var(--v2-font-mono); } /* Pod header: 50px, sans 15/600 title, description inline, meta on the right. */ .v2-pod-header .v2-thread__header-row { min-height: 50px; } .v2-pod-header__meta { display: flex; flex: 0 0 auto; align-items: center; gap: 6px; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); white-space: nowrap; } /* The compact meta is the phone's; both carry the base class, so the compact rule must out-rank the base `display: flex` above it. */ .v2-pod-header__meta.v2-pod-header__meta--compact { display: none; } /* D215: the board is a chip, a board glyph and the count. */ .v2-root button.v2-pod-header__board { display: inline-flex; height: 24px; align-items: center; gap: 5px; padding: 0 8px; border: 0; border-radius: 7px; background: var(--v2-surface); box-shadow: inset 0 0 0 1px var(--v2-border-soft); color: var(--v2-text-secondary); font: 500 11px/1 var(--v2-font-mono); cursor: pointer; } .v2-root button.v2-pod-header__board:hover { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-root button.v2-pod-header__board:focus-visible { outline: none; box-shadow: var(--v2-focus-ring); } /* Owner rename (TASK-419): an inline form in the title line. It wraps at phone width; the input takes the spare room and the buttons keep their content width. */ .v2-pod-header__rename { display: flex; flex: 1 1 auto; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; } .v2-root .v2-pod-header__rename input { flex: 1 1 180px; min-width: 0; max-width: 100%; padding: 6px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); color: var(--v2-text-primary); font: 600 15px/20px var(--v2-font); } .v2-root .v2-pod-header__rename input:focus-visible { box-shadow: var(--v2-focus-ring); outline: 1px solid var(--v2-accent); } .v2-root .v2-pod-header__rename button { flex: 0 0 auto; min-height: 30px; padding: 4px 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); background: var(--v2-surface); color: var(--v2-text-primary); font: 600 12px/16px var(--v2-font); cursor: pointer; } .v2-root .v2-pod-header__rename button[type="submit"] { background: var(--v2-ink); color: var(--v2-on-ink); border-color: var(--v2-ink); } .v2-root .v2-pod-header__rename button:not([type="submit"]):hover:not(:disabled) { background: var(--v2-surface-hover); } .v2-root .v2-pod-header__rename button[type="submit"]:hover:not(:disabled) { background: var(--v2-ink-hover); color: var(--v2-on-ink); } .v2-root .v2-pod-header__rename button:disabled { opacity: .55; cursor: default; } .v2-root .v2-pod-header__rename button:focus-visible { box-shadow: var(--v2-focus-ring); outline: 1px solid var(--v2-accent); } .v2-pod-header__rename-error { flex: 1 0 100%; color: var(--v2-danger); font: 400 12px/16px var(--v2-font); } /* D215: rename is a pencil on the title, out of sight until the title line is hovered or the pencil has keyboard focus. Touch screens show it at rest. */ .v2-root button.v2-pod-header__rename-open { opacity: 0; } .v2-thread__title-line:hover button.v2-pod-header__rename-open, .v2-root button.v2-pod-header__rename-open:focus-visible { opacity: 1; } @media (hover: none) and (pointer: coarse) { .v2-root button.v2-pod-header__rename-open { opacity: 1; } } .v2-root button.v2-thread__back { display: none; } @media (max-width: 760px) { /* The list is a page: full width, no drawer, no backdrop. The list is also the one route where the aside IS a page pane, so the (0,3,0) bounding rule added for TASK-157 reaches it: the aside stops being `calc(100vh - 56px)` and becomes 100% of the shell's content box. Two consequences, both measured by ux-lead at 390 on both banner states (2026-09-25), and both fixed here rather than in that rule — the bounding rule is right for pod, Connectors, Agents and Settings: 1. Nothing reserved the tab bar inside the list's box, so the aside grew to the full 844 and ran under the fixed bar: 0 of 4 tabs hit-testable, on a short list and a long one, banner up or down. The bottom padding below IS that reservation, and its value is the bar's own height — see the guard, which compares the two rather than restating either. The two-class selector is required: a one-class rule of the same name would take the padding back off by document order. 2. The drawer's reset was incomplete — z-index stayed 60. `.v2-shell--list` is a flex container, and a flex item with a z-index other than `auto` forms a stacking context even while static, so the aside painted over the bar (fixed, z 40) and the bar could be neither seen nor tapped. `calc(100vh - 56px)` was dropped rather than kept as a fallback: the rule above outranks it in every render of this shell, so it was already inert. The banner state is fixed by the same padding — main failed the banner case before this change. */ .v2-shell.v2-shell--list { display: flex; flex-direction: column; gap: 0; padding: 0 0 58px; } .v2-shell--list .v2-pods-aside--page { position: static; z-index: auto; width: 100%; transform: none; box-shadow: none; border: 0; } .v2-shell--list .v2-pods { border: 0; border-radius: 0; } .v2-pods-aside:not(.v2-pods-aside--page) { display: none; } .v2-mobile-backdrop { display: none; } .v2-pod-header .v2-thread__header-row { box-sizing: border-box; min-height: 50px; padding: 11px 0; align-items: flex-start; } .v2-pod-header__meta { display: none; } .v2-pod-header__meta.v2-pod-header__meta--compact { display: flex; min-height: 28px; flex: 0 0 auto; white-space: nowrap; } /* TASK-647 item 3: the board link keeps a 44px tap target without growing the 28px meta row (the hit area is a pseudo-element), the name keeps room for the "i" hint, and the compact meta sits closer to the link. */ .v2-root button.v2-pod-header__board--compact { position: relative; } .v2-root button.v2-pod-header__board--compact::before { content: ''; position: absolute; inset: -14px -10px; } .v2-thread__title-line > h1 { max-width: calc(100% - 36px); } .v2-pod-header__meta--compact { gap: 4px; } .v2-root button.v2-thread__back { display: inline-grid; width: 28px; height: 28px; flex: 0 0 28px; place-items: center; padding: 0; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-secondary); } /* Tab bar with labels; the count lives inside the label, one counter. */ .v2-mobile-tabs { height: 58px; padding: 6px 8px 4px; border-top-color: var(--v2-border-soft); } /* Feature pages mount this same bar (V2FeaturePage). Reserve its height on the pane so a scrolling body stops above the fixed bar, not under it. */ .v2-feature { padding-bottom: 58px; } .v2-root button.v2-mobile-tabs__item { display: flex; width: auto; height: 44px; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: 0 6px; background: transparent; /* Icons are controls: the rail's 3:1 grey, not the artboard's 2.58:1 placeholder (D223 standing rule, 11-01). The label sets its own colour. */ color: var(--v2-rail-icon); } .v2-root button.v2-mobile-tabs__item--active, .v2-root button.v2-mobile-tabs__item--active:hover:not(:disabled) { background: transparent; color: var(--v2-text-primary); } .v2-mobile-tabs__icon { display: grid; width: 24px; height: 20px; place-items: center; } .v2-root button.v2-mobile-tabs__item--active .v2-mobile-tabs__icon { color: var(--v2-ink); } /* D223 ruling (Cofounder, 11-01): the artboard's sans family, at the 12px sans floor rather than its 10px. */ .v2-mobile-tabs__label { font: 500 12px/14px var(--v2-font); white-space: nowrap; } /* The artboard greys the whole tab at rest; only the glyph takes that placeholder grey here, so the label text keeps 4.5:1. */ .v2-root button.v2-mobile-tabs__item:not(.v2-mobile-tabs__item--active) .v2-mobile-tabs__label { color: var(--v2-text-muted); } /* D215: the needs-you count is a cobalt badge on the icon, not a sentence in the label. */ .v2-mobile-tabs__icon { position: relative; } .v2-mobile-tabs__count { position: absolute; top: -6px; left: calc(50% + 4px); min-width: 16px; height: 15px; padding: 0 3px; border-radius: 8px; background: var(--v2-accent); color: var(--v2-on-accent); font: 600 11px/15px var(--v2-font-mono); text-align: center; } } /* ---------- Workspace at scale · direction C · PR 2a (composer, attachments, history) ---------- One-line composer with a plus menu, Send only with text, no identity line; images as 156×104 thumbnails with a lightbox, files as chips with a text type badge, code past six lines collapsed; older messages load on scroll with a mono edge line and a Jump-to-latest pill. */ .v2-composer { flex: 0 0 auto; margin: 0 16px 14px; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); } .v2-composer--typing, .v2-composer:focus-within { border-color: var(--v2-border-strong); } .v2-composer__row { display: flex; align-items: flex-end; gap: 8px; min-height: 42px; padding: 7px 8px 7px 10px; } .v2-composer__plus-wrap { position: relative; flex: 0 0 auto; align-self: flex-end; padding-bottom: 2px; } .v2-root button.v2-composer__plus { display: inline-grid; width: 24px; height: 24px; place-items: center; padding: 0; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-secondary); } .v2-root button.v2-composer__plus::before { content: '+'; font: 500 16px/1 var(--v2-font); } .v2-root button.v2-composer__plus:hover:not(:disabled), .v2-root button.v2-composer__plus[aria-expanded="true"] { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-composer__menu { position: absolute; left: 0; bottom: 32px; z-index: 4; display: flex; min-width: 220px; flex-direction: column; gap: 2px; padding: 4px; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); } .v2-root .v2-composer__menu > button { display: block; width: 100%; min-height: 32px; padding: 6px 10px; border: 0; border-radius: 4px; background: transparent; color: var(--v2-text-primary); font: 400 13px/18px var(--v2-font); text-align: left; } .v2-root .v2-composer__menu > button:hover, .v2-root .v2-composer__menu > button:focus-visible { background: var(--v2-surface-hover); outline: none; } .v2-thread__empty-line { display: block; padding: 12px 0; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-composer__tag { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 4px; max-width: 220px; padding: 2px 4px 2px 6px; margin-bottom: 4px; border-radius: 3px; background: var(--v2-accent-soft, #e8ecfb); color: var(--v2-accent-text); font: 500 11px/16px var(--v2-font-mono); text-transform: lowercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-root button.v2-composer__tag-cancel { width: 16px; height: 16px; padding: 0; border: 0; background: transparent; color: inherit; font-size: 14px; line-height: 1; } .v2-composer__field { position: relative; min-width: 0; flex: 1; } .v2-composer__file { display: none; } .v2-root .v2-composer__field > textarea::placeholder { color: var(--v2-text-placeholder); } /* The row carries the focus state on its border; the field itself draws none. */ .v2-root .v2-composer__field > textarea:focus, .v2-root .v2-composer__field > textarea:focus-visible { outline: none; box-shadow: none; border: 0; } .v2-root .v2-composer__field > textarea { display: block; box-sizing: border-box; width: 100%; min-height: 32px; max-height: 112px; padding: 6px 4px; resize: none; border: 0; outline: 0; background: transparent; color: var(--v2-text-primary); font: 400 14px/20px var(--v2-font); } .v2-composer__uploading { flex: 0 0 auto; align-self: center; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-root button.v2-composer__send { display: inline-grid; width: 28px; height: 28px; flex: 0 0 28px; place-items: center; padding: 0; margin-bottom: 0; border: 1px solid var(--v2-ink); border-radius: 4px; background: var(--v2-ink); color: var(--v2-on-ink); font: 500 14px/1 var(--v2-font-mono); } .v2-root button.v2-composer__send:hover:not(:disabled) { background: var(--v2-ink-hover); } .v2-root button.v2-composer__send:disabled { cursor: progress; opacity: 0.6; } .v2-composer__error, .v2-composer__warnings { padding: 0 10px 8px; } /* Attachments */ .v2-msg__thumbs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; } .v2-root button.v2-msg__thumb { display: block; width: 156px; height: 104px; padding: 0; overflow: hidden; border: 1px solid var(--v2-border-soft); border-radius: 4px; background: var(--v2-surface-tint); position: relative; } .v2-root button.v2-msg__thumb:hover { border-color: var(--v2-border-strong); } .v2-msg__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; } .v2-msg__thumb-name { position: absolute; left: 6px; bottom: 6px; max-width: calc(100% - 12px); padding: 1px 5px; border-radius: 3px; background: var(--v2-surface); color: var(--v2-text-secondary); font: 500 11px/14px var(--v2-font-mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-msg__chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; } .v2-root button.v2-msg__chip, .v2-msg__chip { display: inline-flex; align-items: center; gap: 8px; max-width: 100%; min-height: 30px; padding: 5px 8px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-primary); font: 400 12.5px/18px var(--v2-font); text-align: left; } .v2-root button.v2-msg__chip:hover { background: var(--v2-surface-hover); } .v2-msg__chip-ext { flex: 0 0 auto; padding: 1px 5px; border-radius: 3px; background: var(--v2-surface-tint); color: var(--v2-text-secondary); font: 500 11px/14px var(--v2-font-mono); text-transform: uppercase; } .v2-msg__chip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-msg__chip-size { flex: 0 0 auto; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } /* Long code collapses after six lines; expands in place. */ .v2-msg__collapse { position: relative; } .v2-msg__collapse--closed pre { max-height: calc(6 * 1.5 * 12.5px + 20px); overflow: hidden; } /* Long agent prose folds after six lines (6 × 22px). The fade masks the prose itself, so a hovered row keeps its own surface. */ .v2-msg__prose { position: relative; } .v2-msg__prose--closed { max-height: 132px; overflow: hidden; -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent); } .v2-root button.v2-msg__showmore { display: inline-flex; align-items: center; gap: 5px; height: 24px; margin: 6px 0 0; padding: 0 8px 0 6px; border: 0; border-radius: 7px; background: var(--v2-surface); color: var(--v2-text-secondary); box-shadow: inset 0 0 0 1px var(--v2-border); font: 500 12px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-msg__showmore:hover { background: var(--v2-surface-hover); } .v2-root button.v2-msg__showmore:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--v2-accent-text); } .v2-msg__showmore svg { width: 14px; height: 14px; flex: none; transition: transform 160ms; } .v2-msg__showmore[aria-expanded='true'] svg { transform: rotate(180deg); } .v2-root button.v2-msg__more { display: inline-block; margin: 2px 0 6px; padding: 0; border: 0; background: transparent; color: var(--v2-accent-text); font: 500 12.5px/18px var(--v2-font); } .v2-root button.v2-msg__more:hover { text-decoration: underline; } /* Lightbox */ .v2-lightbox { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; background: rgba(16, 24, 40, 0.9); cursor: zoom-out; } .v2-lightbox__image { max-width: min(92vw, 1400px); max-height: 88vh; object-fit: contain; border-radius: 4px; cursor: default; } .v2-lightbox__name { position: absolute; top: 14px; left: 16px; padding: 2px 6px; border-radius: 3px; background: var(--v2-surface); color: var(--v2-text-secondary); font: 500 11px/16px var(--v2-font-mono); } .v2-root button.v2-lightbox__close, .v2-root button.v2-lightbox__nav { position: absolute; display: inline-grid; width: 28px; height: 28px; place-items: center; padding: 0; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-primary); font: 500 16px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-lightbox__close { top: 12px; right: 12px; } .v2-root button.v2-lightbox__nav--prev { left: 12px; top: 50%; transform: translateY(-50%); } .v2-root button.v2-lightbox__nav--next { right: 12px; top: 50%; transform: translateY(-50%); } /* History edge + jump pill */ .v2-thread__edge { display: flex; justify-content: center; padding: 6px 0 10px; } .v2-thread__edge-line { padding: 0; border: 0; background: transparent; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-root button.v2-thread__edge-line { padding: 0; border: 0; background: transparent; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-root button.v2-thread__edge-line { cursor: pointer; } .v2-root button.v2-thread__edge-line:hover { color: var(--v2-text-primary); } .v2-thread__history-status { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 2px 0 10px; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); text-align: center; } .v2-thread__history-status--error { color: var(--v2-text-secondary); } .v2-thread__history-status--viewport { position: absolute; top: 8px; left: 24px; right: 24px; z-index: 4; min-height: 28px; padding: 6px 10px; border: 1px solid var(--v2-border-soft); border-radius: var(--v2-radius-sm); background: var(--v2-surface); pointer-events: none; } .v2-thread__history-status--viewport .v2-thread__history-retry { pointer-events: auto; } .v2-root button.v2-thread__history-retry { padding: 0; border: 0; background: transparent; color: var(--v2-accent-text); font: inherit; text-decoration: underline; cursor: pointer; } /* The wrap is the scroller's last child and STICKS to its bottom edge: a 0-height wrap with an absolute pill resolved `bottom: 12px` against a box at the end of the transcript, ~1100px below the viewport when the pill mounts a viewport up (ux-lead gate on #1579). Sticky needs real height. */ .v2-thread__jump-wrap { position: sticky; bottom: 12px; z-index: 3; display: flex; justify-content: center; height: 28px; pointer-events: none; } .v2-root button.v2-thread__jump { display: inline-flex; align-items: center; gap: 8px; height: 28px; padding: 0 12px; pointer-events: auto; border: 1px solid #dde0e6; border-radius: 14px; background: var(--v2-surface); color: var(--v2-text-primary); font: 600 13px/26px var(--v2-font); white-space: nowrap; } .v2-root button.v2-thread__jump:hover { background: var(--v2-surface-hover); } .v2-thread__jump-count { color: var(--v2-accent-text); font: 700 11px/16px var(--v2-font-mono); } @media (max-width: 760px) { /* Sits above the 56px tab bar; the row itself keeps its desktop shape. */ .v2-composer { margin: 0 12px 64px; } .v2-composer__menu { min-width: 200px; } .v2-root button.v2-msg__thumb { width: calc(50% - 3px); height: 84px; } .v2-composer__tag { max-width: 120px; } } /* ---------- Workspace at scale · direction C · PR 2b (threading restyle, walk-3 misses 51–63) ---------- Runtime tag on agent rows; 20px reaction chips; a two-line quote that jumps to its source; the thread summary is one chip; the expanded thread is one var(--v2-bg-subtle) band with a 2px rule and a Collapse foot; the action strip is a 28px white box top-right on hover (inline under the body on long-press at 390); the Jump pill is white with a cobalt count; transcript avatars are two-tone. */ /* Hover band and the expanded band share the panel colour, not the tint. */ .v2-thread .v2-msg:hover, .v2-thread .v2-msg:focus-within { background: var(--v2-bg-subtle); } .v2-thread .v2-msg { border-radius: 4px; } .v2-thread .v2-msg--landed { background: var(--v2-accent-soft, #e8ecfb); transition: background 0.6s ease; } /* Runtime tag after the time on agent rows. */ .v2-msg__tag { display: inline-block; height: 16px; padding: 0 5px; margin-left: 8px; border-radius: 3px; background: var(--v2-surface-tint); color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); vertical-align: middle; } /* Grouped rows: the time shows in the gutter on hover. */ .v2-msg__gutter-time { position: absolute; left: 0; top: 4px; width: 28px; color: var(--v2-text-placeholder); font: 400 11px/16px var(--v2-font-mono); text-align: center; visibility: hidden; } .v2-thread .v2-msg--grouped:hover .v2-msg__gutter-time { visibility: visible; } /* Two-tone avatars inside the transcript: agents cobalt, humans tint. */ /* Quote: 2px rule, two lines, jumps to the source. */ .v2-thread .v2-msg__quote { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; margin: 2px 0 6px; padding: 0 0 0 10px; border-left: 2px solid var(--v2-border); color: var(--v2-text-secondary); font: 400 13px/17px var(--v2-font); cursor: pointer; max-width: 560px; } .v2-thread .v2-msg__quote:hover { border-left-color: var(--v2-border-strong); } .v2-thread .v2-msg__quote:focus-visible { outline: none; box-shadow: inset 2px 0 0 var(--v2-accent); } .v2-thread .v2-msg__quote-author { color: var(--v2-text-primary); font-weight: 600; } .v2-thread .v2-msg__quote-text { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } /* Reactions: 20px chips, mine in the accent wash. */ .v2-thread .v2-msg__reactions { gap: 6px; margin-top: 6px; } .v2-root .v2-thread button.v2-msg__reaction, .v2-thread .v2-msg__reaction { height: 20px; padding: 0 7px; border: 1px solid var(--v2-border-soft); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-secondary); font: 500 11px/18px var(--v2-font-mono); } .v2-thread .v2-msg__reaction-emoji { font-size: 12px; line-height: 18px; } .v2-thread .v2-msg__reaction-count { font: 500 11px/18px var(--v2-font-mono); } .v2-root .v2-thread button.v2-msg__reaction--mine { border-color: #d4dbf7; background: var(--v2-accent-soft, #e8ecfb); color: var(--v2-accent-text); } .v2-root .v2-thread button.v2-msg__reaction--more { color: var(--v2-accent-text); } /* Action strip: 28px white box, r4, four 24px icons, top-right on hover. */ .v2-thread .v2-msg__strip { top: -14px; right: 0; gap: 2px; padding: 1px; border: 1px solid var(--v2-border-soft); border-radius: 4px; box-shadow: none; } .v2-root .v2-thread button.v2-msg__action { width: 24px; height: 24px; border-radius: 3px; color: #4f5c6e; } .v2-msg__more-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 7; display: flex; min-width: 140px; flex-direction: column; gap: 2px; padding: 4px; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); } .v2-root .v2-msg__more-menu > button { display: block; width: 100%; padding: 6px 10px; border: 0; border-radius: 4px; background: transparent; color: var(--v2-text-primary); font: 400 13px/18px var(--v2-font); text-align: left; } .v2-root .v2-msg__more-menu > button:hover { background: var(--v2-surface-hover); } /* Thread summary chip: faces · N replies · last age. */ .v2-thread .v2-thread-card { margin: 4px 0 0; gap: 10px; } .v2-root .v2-thread button.v2-msg__thread-chip { display: inline-flex; align-items: center; gap: 8px; min-height: 28px; padding: 0 8px 0 4px; border: 1px solid var(--v2-border-soft); border-radius: 4px; background: var(--v2-surface); color: var(--v2-accent-text); font: 600 13px/18px var(--v2-font); } .v2-root .v2-thread button.v2-msg__thread-chip:hover { background: var(--v2-surface-hover); border-color: var(--v2-border); } .v2-thread .v2-thread-card__faces .v2-avatar { width: 16px; height: 16px; border-radius: 4px; border: 1px solid var(--v2-surface); font: 650 11px/1 var(--v2-font-mono); } .v2-thread .v2-thread-card__faces > * + * { margin-left: -4px; } .v2-thread .v2-thread-card__count { color: var(--v2-accent-text); font-weight: 600; } .v2-thread .v2-thread-card__time { color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } /* Expanded thread: the ROOT and its replies share one band (ux-lead 64476 (2)); the chip / rule / replies sit at the text column (28px avatar + 8px gap = 36px). */ .v2-thread .v2-thread-block { margin: 0 0 10px; width: 100%; } .v2-thread .v2-thread-block__inner { margin-left: 36px; } .v2-thread .v2-thread-block--open { background: var(--v2-bg-subtle); border-radius: 4px; padding: 0 8px 6px 0; } .v2-thread .v2-thread-block--open > .v2-msg:hover, .v2-thread .v2-thread-block--open > .v2-msg:focus-within { background: transparent; } .v2-thread .v2-thread-block .v2-thread-card { margin: 2px 0 0; } .v2-thread .v2-thread-replies { margin: 6px 0 0; padding-left: 14px; border-left: 2px solid var(--v2-border); } .v2-thread .v2-thread-replies .v2-msg { grid-template-columns: 24px minmax(0, 1fr); gap: 8px; padding: 4px 0; } .v2-thread .v2-thread-replies .v2-msg:hover { background: transparent; } .v2-thread .v2-thread-replies .v2-msg .v2-avatar { width: 24px; height: 24px; font-size: 12px; } .v2-thread-replies__foot { display: flex; align-items: center; gap: 10px; padding: 6px 0 0; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-root button.v2-thread-replies__collapse, .v2-root button.v2-thread-replies__more { padding: 0; border: 0; background: transparent; color: var(--v2-accent-text); font: 500 13px/18px var(--v2-font); cursor: pointer; } .v2-root button.v2-thread-replies__more { display: block; margin: 2px 0 4px; } .v2-root button.v2-thread-replies__follow { margin-left: auto; padding: 0; border: 0; background: transparent; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); cursor: pointer; } .v2-root button.v2-thread-replies__follow--on { color: var(--v2-accent-text); } /* Mention token: wash + cobalt (ux-lead 64476 (7)); the row tint stays. */ .v2-thread .v2-msg__mention { background: #e8ecfb; color: var(--v2-accent-text); border-radius: 3px; padding: 0 4px; } /* Transcript avatars are two-tone squares (ux-lead 64476 (1)): human tint + #4f5c6e initials, agent cobalt + white initials; a photo still wins. */ .v2-thread .v2-avatar--flat { border: 0; box-shadow: none; border-radius: 4px; font: 650 12px/1 var(--v2-font); letter-spacing: 0.02em; } .v2-thread .v2-avatar--flat-human { background: #f2f4f7; color: #4f5c6e; } .v2-thread .v2-avatar--flat-agent { background: var(--v2-accent); color: var(--v2-bg); } .v2-thread .v2-thread-replies .v2-msg .v2-avatar--flat { font: 650 12px/1 var(--v2-font); } .v2-thread .v2-thread-card__faces .v2-avatar--flat { font: 650 11px/1 var(--v2-font-mono); } .v2-root .v2-thread button.v2-thread-replies__aim { margin-left: auto; padding: 0; color: var(--v2-text-muted); font: 500 12px/16px var(--v2-font); } /* Jump pill: white, #dde0e6 border, r14, ink 13/600, cobalt count (walk-3 miss 58). */ /* Composer aim chip (walk-3 miss 59). */ .v2-composer__aim { background: var(--v2-accent-soft, #e8ecfb); color: var(--v2-accent-text); } /* The reveal is gated on capability in the row — `matchMedia('(hover: none)')`, with no width term and no `(pointer: coarse)` — so its placement matches that query EXACTLY (sprint-review 64468 + 64485). A comma'd `(pointer: coarse)` would style stylus/hybrid machines where `isHoverless()` is false and the reveal never fires: a dead rule. This block sits AFTER the `.v2-thread .v2-msg__strip` rules it overrides (11229) for the same reason the double pod-header meta needed source order, not specificity. */ @media (hover: none) { /* Long-press reveals the strip inline under the body. */ .v2-thread .v2-msg { -webkit-touch-callout: none; } /* The row is a 28px | 1fr grid and the strip precedes the body in DOM: left to auto-place, a static strip takes the body's cell and the body drops into the avatar column (one word per line — 390 walk). Pin it. */ .v2-thread .v2-msg--reveal { background: var(--v2-bg-subtle); row-gap: 6px; } .v2-thread .v2-msg--reveal .v2-msg__strip { position: static; grid-column: 2; grid-row: 2; justify-self: start; display: inline-flex; margin: 0; opacity: 1; pointer-events: auto; } } @media (max-width: 760px) { /* Sizing is a width question, not a capability one. */ .v2-root .v2-thread button.v2-msg__action { width: 24px; height: 24px; } .v2-root .v2-thread button.v2-msg__thread-chip { min-height: 32px; } .v2-thread .v2-msg__gutter-time { display: none; } } /* Direction C Activity board: a 52px bar over a readable 760px column. The composer remains under the explicit destination ruling. */ .v2-activity { position: relative; width: 100%; max-width: none; padding: 0 0 28px; } .v2-activity__header { min-height: 64px; align-items: baseline; padding: 20px 16px 4px; gap: 16px; border-bottom: 0; overflow: visible; } .v2-activity__title { font: 700 32px/36px var(--v2-font-display); letter-spacing: -0.03em; white-space: nowrap; } .v2-activity__controls { position: absolute; top: 22px; right: 16px; gap: 8px; z-index: 2; } .v2-activity__scope { display: flex; flex-wrap: nowrap; gap: 2px; position: relative; padding: 3px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); } .v2-activity__scope-menu { position: absolute; top: calc(100% + 4px); right: 0; display: grid; gap: 2px; width: min(300px, 85vw); max-height: 240px; overflow-y: auto; padding: 4px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); } .v2-root button.v2-activity__scope-button { min-height: 30px; max-width: 150px; padding: 0 9px; border: 0; border-radius: calc(var(--v2-radius-sm) - 2px); background: transparent; color: var(--v2-text-secondary); font: 600 11px/16px var(--v2-font-mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-root button.v2-activity__scope-button--active { background: var(--v2-surface-hover); color: var(--v2-text-primary); font-weight: 600; } .v2-root button.v2-activity__scope-button--menu { max-width: none; white-space: normal; text-align: left; } .v2-root button.v2-activity__window-button { font: 600 11px/16px var(--v2-font-mono); } .v2-activity__sections { width: min(100%, 760px); margin: 28px auto 0; gap: 34px; } .v2-activity__section-heading { margin-bottom: 10px; } .v2-activity__queue { gap: 10px; } .v2-activity__queue-row { grid-template-columns: 28px minmax(0, 1fr) auto; padding: 11px; border: 2px solid var(--v2-accent); border-radius: var(--v2-radius); background: var(--v2-surface); } .v2-activity__queue-row:hover { background: var(--v2-surface); } .v2-activity__queue-row--decision { border-color: var(--v2-accent); box-shadow: none; } .v2-activity__queue-row--approval { border-color: var(--v2-accent); box-shadow: none; } .v2-activity__queue-row--settled, .v2-activity__queue-row--onboarding { padding: 12px; border: 1px solid var(--v2-border); } .v2-activity__queue-kind { font: 500 11px/16px var(--v2-font-mono); text-transform: lowercase; } .v2-activity__queue-topline strong { font-size: 14px; line-height: 20px; } .v2-activity__queue-copy p { font-size: 14px; line-height: 20px; } .v2-activity__queue-more { min-height: 36px; border: 1px solid var(--v2-accent); color: var(--v2-accent); font: 600 12px/16px var(--v2-font); } .v2-activity__empty--plain { min-height: 0; padding: 18px 20px; border: 1px dashed var(--v2-border); border-radius: var(--v2-radius); align-items: flex-start; text-align: left; } .v2-activity__moved-list { display: grid; gap: 10px; } .v2-activity__moved-group { border: 1px solid var(--v2-border); border-radius: 6px; overflow: hidden; background: var(--v2-surface); } .v2-activity__moved-head { display: flex; justify-content: space-between; padding: 9px 12px; border-bottom: 1px solid var(--v2-border-soft); color: var(--v2-text-secondary); font: 400 11px/16px var(--v2-font-mono); } .v2-activity__moved-lines { display: grid; } .v2-activity__moved-line { display: grid; grid-template-columns: minmax(100px, auto) minmax(0, 1fr) auto; gap: 8px; padding: 8px 12px; font-size: 13px; line-height: 18px; } .v2-activity__moved-line + .v2-activity__moved-line { border-top: 1px solid var(--v2-border-soft); } .v2-activity__moved-line strong { font-weight: 600; color: var(--v2-text-primary); } .v2-activity__moved-line span { min-width: 0; overflow-wrap: anywhere; } .v2-activity__moved-line time { color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); white-space: nowrap; } .v2-activity__moved-cap-note { display: block; padding: 6px 12px 8px; color: var(--v2-text-muted); font: 400 11px/16px var(--v2-font-mono); } .v2-root button.v2-activity__moved-more { width: 100%; padding: 8px 12px; border: 0; border-top: 1px solid var(--v2-border-soft); background: transparent; color: var(--v2-accent-text); text-align: left; font: 600 12px/16px var(--v2-font); } @media (max-width: 640px) { .v2-activity__header { min-height: 56px; align-items: baseline; flex-direction: row; flex-wrap: wrap; padding: 16px 12px 4px; gap: 8px; } .v2-activity__sections { margin-top: 20px; padding: 0 12px; } .v2-activity__moved-line { grid-template-columns: minmax(0, 1fr) auto; } .v2-activity__moved-line span { grid-column: 1 / -1; grid-row: 2; } } /* Direction C owns the full pane edge. The generic feature wrapper is padded for legacy pages, which would inset the Activity bar and make its 52px contract impossible to reach. */ .v2-feature--activity > .v2-feature__body { padding: 0 0 28px; } .v2-feature--activity .v2-feature__legacy { max-width: none; } .v2-activity__compose { width: min(calc(100% - 24px), 760px); margin: 20px auto 0; } .v2-root button.v2-activity__queue-more { border: 0; background: transparent; color: var(--v2-accent); font: 600 12px/16px var(--v2-font); } .v2-root button.v2-activity__queue-more:hover:not(:disabled) { background: var(--v2-accent-soft); color: var(--v2-accent); } .v2-root .v2-activity__scope-menu button.v2-activity__scope-button { width: 100%; max-width: none; } .v2-root .v2-activity__queue-actions button.v2-activity__option { min-height: 32px; border-radius: var(--v2-radius-sm); } /* Rail badge (66390): the exact count at any size — 118 reads as 118. Mono, bordered, cobalt, no clip. */ .v2-rail__item-icon .MuiBadge-badge { top: -7px; right: -14px; height: 15px; min-width: 16px; padding: 0 3px; border: 0; border-radius: 8px; background: var(--v2-accent); box-shadow: 0 0 0 2px var(--v2-shell-bg); color: var(--v2-on-accent); font: 600 11px/15px var(--v2-font-mono); transform: none; white-space: nowrap; } /* TASK-363: only the Activity badge is offset inward. Three-digit counts (230, 1234) overflowed the rail at -14px; the other rail badges keep the base offset. */ .v2-rail__item-icon .v2-rail__badge--activity .MuiBadge-badge { right: -6px; } .v2-root .v2-activity__queue-actions button.v2-activity__option--other { border-color: transparent; background: transparent; color: var(--v2-accent-text); padding: 0 4px; } /* ≤760 (66390): the two toggles stack. The card-action stack lives in the trailing ≤760 block at the end of the Activity rules, after every row/action rule it must outrank. */ @media (max-width: 760px) { .v2-activity__controls { flex-direction: column; align-items: stretch; } } .v2-root .v2-activity__queue-row--decision .v2-activity__queue-mark { background: var(--v2-accent); color: #fff; } /* Categories are marks, only the deciding act is a word (direction A). The mark holds a 16px glyph; a secondary act is a 32px square holding one, its word in the title and the accessible name. Nothing is hidden in a menu. */ .v2-root .v2-activity__queue-mark svg { width: 16px; height: 16px; } .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--icon { width: 32px; min-width: 32px; padding: 0; justify-content: center; } .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--icon svg { width: 16px; height: 16px; flex: none; } .v2-activity__queue-row .v2-activity__queue-actions { grid-column: 3; grid-row: 1; max-width: 320px; justify-content: flex-end; flex-wrap: wrap; margin-top: 0; } .v2-activity__queue-row .v2-activity__option-choice { flex: 0 1 auto; max-width: 150px; } .v2-activity__queue-row .v2-activity__option { white-space: normal; } /* Opening a reply or a free-text ruling gives that editor a full content row. */ .v2-activity__queue-row .v2-activity__queue-actions:has(textarea) { grid-column: 2 / -1; grid-row: 2; max-width: none; justify-content: flex-start; } .v2-activity__empty--plain span { color: var(--v2-text-secondary); font: 400 13px/18px var(--v2-font); } /* Keep filters on a separate row when the pane cannot fit them beside the title. Both rows stay in normal reading order, without a clipped title. */ @media (max-width: 1100px) { .v2-activity__controls { position: relative; top: auto; right: auto; display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; width: 100%; padding: 10px 12px; border-bottom: 1px solid var(--v2-border-soft); } .v2-activity__window { width: auto; flex: 0 0 auto; } .v2-activity__scope { min-width: 0; max-width: 100%; flex-wrap: wrap; } } @media (max-width: 640px) { .v2-activity__queue-row { grid-template-columns: 28px minmax(0, 1fr); } .v2-root .v2-activity__queue-actions button.v2-activity__option { min-height: 44px; } .v2-activity__queue-row .v2-activity__queue-actions { grid-column: 1 / -1; grid-row: auto; max-width: none; justify-content: flex-start; } .v2-activity__queue-row .v2-activity__option-choice { max-width: 100%; } } /* Decision alternatives are one inline line below the question (ux-lead 66400 fix 4): 32px options in authored order, primary cobalt, the rest bordered, `Other…` as cobalt text beside them, Open at the end. These rules intentionally come after the generic queue-row overrides above so the options are neither squeezed into the 320px action column nor capped at 150px each. */ .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__queue-actions { grid-column: 1 / -1; grid-row: auto; max-width: none; width: 100%; justify-content: flex-start; align-items: flex-start; flex-direction: row; flex-wrap: wrap; gap: 8px; } .v2-activity__queue-row.v2-activity__queue-row--decision { align-items: start; row-gap: 12px; } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__option-choice { display: flex; flex-direction: column; gap: 2px; width: auto; flex: 0 1 auto; max-width: 280px; } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__option-choice button { justify-content: center; min-height: 32px; padding-block: 0; padding-inline: 12px; text-align: left; line-height: 20px; white-space: normal; } /* The footer's children (Other…, the free-text editor, Open) flow on the same line. */ .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__decision-footer { display: contents; } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__decision-other { flex: 1 1 100%; } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__option-choice button.v2-activity__option:not(.v2-activity__option--primary):hover:not(:disabled) { background: var(--v2-surface-hover); color: var(--v2-text-primary); } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__option-recommended { display: block; color: var(--v2-text-muted); font: 500 11px/14px var(--v2-font-mono); } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__option-description { color: var(--v2-text-secondary); font-size: 14px; line-height: 20px; } .v2-activity__decision-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; width: 100%; } /* ≤760 (ux-lead 66428; sprint-review 66435 — the ruling's number is 760, not 640, so the 641–760 band stacks too): decision options stack like every other action — 44px, full width. This block sits AFTER the inline option rules above so it wins at equal specificity. */ @media (max-width: 760px) { /* Every card action drops under the context line at 44px full width (66390 / 66438 at 720): same selectors as the desktop rules above so this block wins by order, not by luck. */ .v2-activity__queue-row { grid-template-columns: 28px minmax(0, 1fr); } .v2-activity__queue-row .v2-activity__queue-actions { grid-column: 1 / -1; grid-row: auto; max-width: none; justify-content: flex-start; flex-wrap: wrap; } .v2-root .v2-activity__queue-actions > button { flex: 1 1 100%; min-height: 44px; } /* The reply editor's nested Send only grows in HEIGHT (sprint-review 66493/66498): a descendant rule here gave it flex-basis 100% and it ate the textarea (489px Send beside a 139px input). */ .v2-root .v2-activity__reply > button { min-height: 44px; } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__option-choice { flex: 1 1 100%; max-width: none; } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__option-choice button { width: 100%; min-height: 44px; } .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__decision-footer > button { flex: 1 1 100%; min-height: 44px; } /* Icon acts stay 44px squares under 760 — the full-width `> button` rule above would stretch them. */ .v2-root .v2-activity__queue-actions button.v2-activity__queue-action--icon { width: 44px; min-width: 44px; flex: none; } .v2-root .v2-activity__queue-row.v2-activity__queue-row--decision .v2-activity__decision-footer > button.v2-activity__queue-action--icon { flex: none; width: 44px; min-width: 44px; } } /* Get started — day zero (ux-lead 66658/66666, board 66663/66664). One bordered card above Needs you; a step is not an ask: no ring, no count, no badge. Ink numbered marks, dividers, 32px buttons at desktop (the current step ink, later steps bordered), 44 full width at ≤760. */ .v2-activity__start { width: min(100%, 760px); margin: 20px auto 0; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); overflow: hidden; } .v2-activity__start-head { display: flex; align-items: baseline; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--v2-border-soft); } .v2-activity__start-head h2 { margin: 0; font: 600 14px/20px var(--v2-font); color: var(--v2-text-primary); } .v2-activity__start-kicker { color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); } .v2-activity__start-row { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: 12px; align-items: start; padding: 12px 14px; border-bottom: 1px solid var(--v2-border-soft); } .v2-activity__start-row:last-child { border-bottom: 0; } .v2-activity__start-num { display: grid; place-items: center; width: 28px; height: 28px; border-radius: var(--v2-radius-sm); background: var(--v2-ink); color: var(--v2-on-ink); font: 500 11px/16px var(--v2-font-mono); } .v2-activity__start-copy { min-width: 0; } .v2-activity__start-copy strong { display: block; color: var(--v2-text-primary); font: 600 14px/20px var(--v2-font); } .v2-activity__start-copy p { margin: 2px 0 0; color: var(--v2-text-secondary); font: 400 14px/20px var(--v2-font); } .v2-activity__start-act { display: flex; align-items: center; } .v2-root .v2-activity__start-act button { min-height: 32px; padding: 0 12px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); color: var(--v2-text-primary); font: 600 13px/18px var(--v2-font); white-space: nowrap; } .v2-root .v2-activity__start-act button.v2-activity__start-cta--current { border-color: var(--v2-ink); background: var(--v2-ink); color: var(--v2-on-ink); } @media (max-width: 760px) { .v2-activity__start { width: auto; margin: 16px 12px 0; } .v2-activity__start-head { flex-direction: column; align-items: flex-start; gap: 2px; } .v2-activity__start-row { grid-template-columns: 28px minmax(0, 1fr); } .v2-activity__start-act { grid-column: 1 / -1; } .v2-root .v2-activity__start-act button { width: 100%; min-height: 44px; } } /* --------------------------------------------------------------------------- Your Team — direction C, Signal (docs/design/signal-identity.md §4 "Cards in a grid"). One card per agent; the mark's colour is the state; the one that needs you carries the 2px cobalt ring. Ink acts (Hire, Answer); secondaries are bordered; status is mono because it is data. --------------------------------------------------------------------------- */ .v2-team { display: flex; flex-direction: column; gap: 24px; } .v2-team__head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; } .v2-team__heading { display: flex; align-items: baseline; gap: 12px; min-width: 0; } .v2-team__title { margin: 0; font: 700 32px/1.1 var(--v2-font-display); letter-spacing: -0.03em; color: var(--v2-text-primary); } .v2-team__meta { font-size: 13px; color: var(--v2-text-muted); white-space: nowrap; } .v2-team__actions { display: flex; gap: 8px; flex-shrink: 0; } .v2-root button.v2-team__byo { height: 36px; padding: 0 14px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-primary); font: 600 13px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-team__byo:hover { background: var(--v2-surface-hover); } /* Ink acts (signal-identity §2): Hire is the page's one filled control. */ .v2-root button.v2-team__hire { height: 36px; padding: 0 14px; border: 1px solid #101828; border-radius: 4px; background: #101828; color: #fff; font: 600 13px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-team__hire:disabled { opacity: 0.5; cursor: default; } .v2-team__notice { font-size: 13px; color: var(--v2-text-secondary); } .v2-team__notice--ok { color: var(--v2-text-primary); } .v2-team__redeem { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .v2-team__redeem-input { height: 36px; padding: 0 12px; border: 1px solid var(--v2-border); border-radius: 4px; font: 400 14px/20px var(--v2-font); } .v2-team__redeem-error { color: var(--v2-text-primary); font-size: 13px; } .v2-root button.v2-team__link { padding: 0; border: 0; background: transparent; color: var(--v2-accent-text); font: 500 13px/20px var(--v2-font); cursor: pointer; } .v2-team__error { font-size: 13px; color: var(--v2-text-primary); border: 1px solid var(--v2-border); border-radius: 4px; padding: 10px 12px; } .v2-team__empty { border: 1px dashed var(--v2-border); border-radius: 4px; padding: 20px; } .v2-team__empty-title { font: 700 var(--v2-fs-feature)/1.2 var(--v2-font-display); letter-spacing: -0.02em; margin-bottom: 6px; } .v2-team__empty-text { font-size: 13px; color: var(--v2-text-secondary); } .v2-team__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; } .v2-team-card { display: flex; flex-direction: column; gap: 10px; padding: 16px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); min-width: 0; } /* The one that needs you: a ring, never a tinted background (state grammar §3). */ .v2-team-card--needsYou { border: 2px solid var(--v2-accent); padding: 15px; } .v2-team-card--own { border-style: dashed; } .v2-team-card__head { display: flex; align-items: center; gap: 10px; min-width: 0; } .v2-root button.v2-team-card__mark { width: 40px; height: 40px; flex-shrink: 0; display: grid; place-items: center; border: 0; border-radius: 4px; font: 600 12px/1 var(--v2-font); letter-spacing: 0.02em; text-transform: uppercase; cursor: pointer; overflow: hidden; padding: 0; } .v2-root button.v2-team-card__mark img { width: 100%; height: 100%; object-fit: cover; } .v2-root button.v2-team-card__mark .v2-avatar { width: 100%; height: 100%; border: 0; border-radius: inherit; } .v2-root button.v2-team-card__mark--needsYou { background: var(--v2-accent); color: var(--v2-bg); } .v2-root button.v2-team-card__mark--working { background: var(--v2-text-primary); color: var(--v2-bg); } .v2-root button.v2-team-card__mark--idle { background: var(--v2-border-soft); color: #4f5c6e; } .v2-team-card__title { min-width: 0; } /* A primary identifier never one-line-ellipsizes (craft audit rule 1, #568): two lines, then clamp; min-width 0 so the grid column can shrink under it. */ .v2-team-card__name { font: 700 18px/1.2 var(--v2-font-display); letter-spacing: -0.02em; color: var(--v2-text-primary); overflow-wrap: anywhere; white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-width: 0; } .v2-team-card__status { margin-top: 2px; font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-team-card__status--needsYou, .v2-team-card__status--working { color: var(--v2-accent-text); } /* The ask is the line's content — it wraps, it never ellipsizes (66246 (3)). */ .v2-team-card__status--needsYou { white-space: normal; overflow: visible; text-overflow: clip; } .v2-team-card__status--working .v2-team-card__dot { animation: v2-team-pulse 1.6s ease-in-out infinite; } @keyframes v2-team-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } } @media (prefers-reduced-motion: reduce) { .v2-team-card__status--working .v2-team-card__dot { animation: none; } } .v2-team-card__desc { margin: 0; font-size: 13px; line-height: 18px; color: var(--v2-text-secondary); } .v2-team-card__pods { display: flex; gap: 6px; flex-wrap: wrap; } .v2-team-card__pod { font: 500 11px/16px var(--v2-font-mono); padding: 2px 6px; border: 1px solid var(--v2-border); border-radius: 4px; color: var(--v2-text-secondary); } .v2-team-card__command { display: block; padding: 8px 10px; border-radius: 4px; background: #101828; color: #fff; font: 500 14px/20px var(--v2-font-mono); white-space: pre-wrap; overflow-wrap: anywhere; } .v2-team-card__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; } /* Where the seat runs: a cloud (Commonly) or a laptop (your computer), top-right. */ .v2-team-card__where { display: inline-flex; flex: none; margin-left: auto; align-self: flex-start; color: var(--v2-text-muted); } /* Hosted meter: the server's count against the server's cap, as a bar and a mono line. */ .v2-team-card__meter { display: flex; align-items: center; gap: 10px; } .v2-team-card__meter-track { flex: 1; min-width: 0; height: 4px; border-radius: 2px; background: var(--v2-border-soft); overflow: hidden; } .v2-team-card__meter-fill { display: block; height: 100%; background: var(--v2-accent); } .v2-team-card__meter-text { font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-muted); white-space: nowrap; } .v2-root button.v2-team-card__answer { height: 32px; padding: 0 12px; border: 1px solid #101828; border-radius: 4px; background: #101828; color: #fff; font: 600 13px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-team-card__talk { height: 32px; padding: 0 12px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-surface); color: var(--v2-text-primary); font: 600 13px/1 var(--v2-font); cursor: pointer; } .v2-root button.v2-team-card__talk:hover { background: var(--v2-surface-hover); } .v2-root button.v2-team-card__talk:disabled { color: var(--v2-text-placeholder); cursor: default; } .v2-team__internal { display: flex; flex-direction: column; gap: 8px; } .v2-root button.v2-team__internal-toggle { font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-muted); } .v2-team__internal-list { display: flex; gap: 6px; flex-wrap: wrap; } @media (max-width: 760px) { .v2-team__head { flex-direction: column; align-items: flex-start; } /* The title never wraps beside its meta: stack them (66246 (1)). */ .v2-team__heading { flex-direction: column; align-items: flex-start; gap: 2px; } .v2-team__meta { white-space: normal; } .v2-team__grid { grid-template-columns: repeat(1, minmax(0, 1fr)); } .v2-root button.v2-team-card__answer, .v2-root button.v2-team-card__talk, .v2-root button.v2-team__byo, .v2-root button.v2-team__hire { min-height: 44px; } } /* --------------------------------------------------------------------------- Artifacts — direction C, PR 5 (ScaleArtifacts.dc.html). Every file and page shared in your pods. Display head + muted meta; two segment groups on one grammar (bordered white group, active = tint + ink 600); a bordered search; a plain table whose numbers are mono; the ext chip is the file's own extension, bordered mono, never a colour square. --------------------------------------------------------------------------- */ .v2-feature--artifacts > .v2-feature__body { padding: 0 0 28px; } .v2-feature--artifacts .v2-feature__legacy { max-width: none; } .v2-artifacts { display: flex; flex-direction: column; gap: 20px; width: 100%; padding: 20px 16px 0; } .v2-artifacts__head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; } .v2-artifacts__title { margin: 0; font: 700 32px/1.1 var(--v2-font-display); letter-spacing: -0.03em; color: var(--v2-text-primary); } .v2-artifacts__controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } .v2-artifacts__seg { position: relative; display: flex; flex-wrap: nowrap; gap: 2px; padding: 3px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); } .v2-root button.v2-artifacts__seg-button { min-height: 30px; max-width: 150px; padding: 0 9px; border: 0; border-radius: calc(var(--v2-radius-sm) - 2px); background: transparent; color: var(--v2-text-secondary); font: 600 11px/16px var(--v2-font-mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .v2-root button.v2-artifacts__seg-button--active { background: var(--v2-surface-hover); color: var(--v2-text-primary); font-weight: 600; } .v2-root button.v2-artifacts__seg-button--menu { width: 100%; max-width: none; white-space: normal; text-align: left; } .v2-artifacts__seg-menu { position: absolute; top: calc(100% + 4px); right: 0; z-index: 3; display: grid; gap: 2px; width: min(300px, 85vw); max-height: 240px; overflow-y: auto; padding: 4px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); } .v2-artifacts__search { display: flex; align-items: center; gap: 8px; min-width: 220px; height: 36px; margin-left: auto; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); background: var(--v2-surface); } .v2-artifacts__search input { flex: 1 1 auto; min-width: 0; border: 0; outline: 0; background: transparent; color: var(--v2-text-primary); font: 400 13px/18px var(--v2-font); } .v2-artifacts__search input::placeholder { color: var(--v2-text-muted); } .v2-artifacts__search:focus-within { border-color: var(--v2-accent); } .v2-artifacts__search-key { color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); } .v2-artifacts__table-wrap { overflow-x: auto; border: 1px solid var(--v2-border); border-radius: 6px; background: var(--v2-surface); } .v2-artifacts__table { width: 100%; border-collapse: collapse; font: 400 13px/18px var(--v2-font); color: var(--v2-text-primary); } .v2-artifacts__table th { padding: 8px 12px; border-bottom: 1px solid var(--v2-border-soft); color: var(--v2-text-muted); font: 500 11px/16px var(--v2-font-mono); text-align: left; text-transform: lowercase; white-space: nowrap; } .v2-artifacts__table td { padding: 9px 12px; border-bottom: 1px solid var(--v2-border-soft); vertical-align: middle; } .v2-artifacts__table tr:last-child td { border-bottom: 0; } .v2-artifacts__row:hover td { background: var(--v2-surface-hover); } .v2-artifacts__file { display: flex; align-items: center; gap: 10px; min-width: 0; } .v2-artifacts__ext { display: inline-flex; align-items: center; justify-content: center; min-width: 34px; height: 20px; padding: 0 5px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); color: var(--v2-text-secondary); font: 500 11px/14px var(--v2-font-mono); letter-spacing: 0.02em; } .v2-artifacts__pod-line { display: none; color: var(--v2-text-secondary); font: 500 11px/16px var(--v2-font-mono); } .v2-root button.v2-artifacts__name { min-width: 0; padding: 0; border: 0; background: transparent; color: var(--v2-text-primary); font: 600 13px/18px var(--v2-font); text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-root button.v2-artifacts__name:hover { color: var(--v2-accent-text); } .v2-artifacts__mono { color: var(--v2-text-secondary); font: 500 11px/16px var(--v2-font-mono); white-space: nowrap; } .v2-artifacts__foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; } .v2-root button.v2-artifacts__more { padding: 6px 4px; border: 0; background: transparent; color: var(--v2-accent-text); font: 600 12px/16px var(--v2-font); } .v2-artifacts__empty { padding: 18px 20px; border: 1px dashed var(--v2-border); border-radius: var(--v2-radius); color: var(--v2-text-secondary); font: 400 13px/18px var(--v2-font); } .v2-artifacts__error { padding: 12px 14px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius); color: var(--v2-text-primary); font: 400 13px/18px var(--v2-font); } .v2-artifacts__loading { display: grid; place-items: center; padding: 24px; } /* Inspector Files pane: the same rows as needs-you, an ext chip in front, All N files as cobalt text. */ .v2-root button.v2-workspace-inspector__file { display: flex; align-items: center; justify-content: flex-start; gap: 8px; width: 100%; padding: 7px 4px; border: 0; background: transparent; color: var(--v2-text-primary); font: 400 13px/18px var(--v2-font); text-align: left; } .v2-root button.v2-workspace-inspector__file > span:nth-child(2) { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v2-root button.v2-workspace-inspector__file:hover { background: var(--v2-surface-hover); } .v2-workspace-inspector__ext { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; min-width: 30px; height: 18px; padding: 0 4px; border: 1px solid var(--v2-border); border-radius: var(--v2-radius-sm); color: var(--v2-text-secondary); font: 500 11px/14px var(--v2-font-mono); } .v2-root button.v2-workspace-inspector__all-files { padding: 6px 4px 2px; border: 0; background: transparent; color: var(--v2-accent-text); font: 600 12px/16px var(--v2-font); text-align: left; } /* ≤760 (ux-lead 66462): no sideways scroll — keep file / kind / when, fold the pod under the name as a mono line, hide pod / shared-by / size; the head stays display 32. */ @media (max-width: 760px) { .v2-artifacts { padding: 16px 12px 0; gap: 16px; } .v2-artifacts__controls { flex-direction: column; align-items: stretch; } .v2-artifacts__search { margin-left: 0; } .v2-artifacts__table { table-layout: fixed; } .v2-artifacts__table th:nth-child(3), .v2-artifacts__table td:nth-child(3), .v2-artifacts__table th:nth-child(4), .v2-artifacts__table td:nth-child(4), .v2-artifacts__table th:nth-child(6), .v2-artifacts__table td:nth-child(6) { display: none; } .v2-artifacts__table th:nth-child(2), .v2-artifacts__table td:nth-child(2) { width: 64px; } .v2-artifacts__table th:nth-child(5), .v2-artifacts__table td:nth-child(5) { width: 52px; } .v2-artifacts__file { flex-wrap: wrap; row-gap: 2px; } .v2-artifacts__pod-line { display: block; flex: 1 1 100%; } .v2-root button.v2-artifacts__name { white-space: normal; overflow-wrap: anywhere; } } /* TASK-443: priority is text contrast; ownership is a lease, following is receipt. */ .v2-board__col { border-radius: 6px; gap: 8px; } .v2-board__col-name { font-size: 13px; line-height: 20px; letter-spacing: 0; text-transform: none; } .v2-board__col-count { font: 500 11px/16px var(--v2-font-mono); background: none; padding: 0; } .v2-board__card { border-radius: 4px; } .v2-root button.v2-board__card-main { gap: 6px; padding: 12px; } .v2-board__card-kicker { display: flex; align-items: center; gap: 6px; } .v2-board__card-id { font: 500 11px/16px var(--v2-font-mono); } .v2-board__priority { display: inline-block; padding: 0 5px; border: 1px solid var(--v2-prio-edge); border-radius: 4px; font: 500 11px/16px var(--v2-font-mono); color: var(--v2-prio-ink); background: none; } .v2-board__priority--p0 { background: var(--v2-prio-p0-bg); border-color: var(--v2-prio-p0-bg); color: var(--v2-prio-p0-fg); } .v2-board__priority--p2 { color: var(--v2-prio-p2-fg); } .v2-board__col--blocked .v2-board__col-name { color: var(--v2-status-blocked); } .v2-board__card--blocked { box-shadow: inset 3px 0 0 var(--v2-status-blocked-edge); } .v2-board__card-title { font-size: 14px; line-height: 20px; } .v2-board__owner-line { display: flex; align-items: center; gap: 6px; font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-secondary); } .v2-board__owner-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; } .v2-board__owner-dot--live { background: var(--v2-status-live); } .v2-board__owner-dot--not-claimed { border: 1px dashed var(--v2-status-pending); } .v2-board__owner-dot--expired { border: 1px solid var(--v2-status-idle); background: none; } .v2-board__card--done { border-color: var(--v2-border-soft); } .v2-board__card--done .v2-board__card-title { color: var(--v2-text-secondary); } .v2-root button.v2-board__card-move { min-height: 32px; padding: 0 10px; border-radius: 4px; } .v2-board__overlay { background: color-mix(in srgb, var(--v2-text-primary) 32%, transparent); align-items: flex-start; padding-top: 72px; } .v2-board .v2-modal { border-radius: 6px; box-shadow: none; } .v2-board__detail { width: min(560px, 100%); max-height: calc(100dvh - 96px); } .v2-board__detail .v2-modal__head { padding: 20px 24px 16px; border-bottom: 1px solid var(--v2-border-soft); } .v2-board__detail .v2-modal__title { font: 700 20px/26px var(--v2-font-display); letter-spacing: -0.02em; min-width: 0; overflow-wrap: anywhere; } .v2-board__detail .v2-modal__body { padding: 16px 24px 24px; display: grid; gap: 20px; } .v2-root .v2-board__detail button.v2-modal__close { width: 32px; height: 32px; border: 1px solid var(--v2-border); border-radius: 4px; flex-shrink: 0; } .v2-board__grab { display: none; } /* D215 task board: details open in a 400px right drawer, not a centred modal. */ .v2-board .v2-board__overlay--drawer { align-items: stretch; justify-content: flex-end; padding-top: 0; } .v2-board .v2-board__drawer { width: 400px; max-width: 100%; height: 100%; max-height: none; border-radius: 14px 0 0 14px; box-shadow: var(--v2-shadow-lg); } .v2-board__status-segment { display: inline-flex; max-width: 100%; border: 1px solid var(--v2-border); border-radius: 6px; overflow: hidden; } .v2-root button.v2-board__status-option { min-height: 32px; padding: 0 12px; border: 0; border-radius: 0; background: var(--v2-bg); color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; } .v2-root button.v2-board__status-option + button.v2-board__status-option { border-left: 1px solid var(--v2-border-soft); } .v2-root button.v2-board__status-option[aria-checked="true"] { background: var(--v2-surface); color: var(--v2-text-primary); } .v2-root button.v2-board__status-option:disabled { cursor: default; } .v2-root button.v2-board__updates-toggle { justify-self: start; min-height: 32px; padding: 0; border: 0; background: none; color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; text-decoration: underline; } .v2-board__ownership { margin: 0; display: grid; grid-template-columns: 112px minmax(0, 1fr); border: 1px solid var(--v2-border-soft); border-radius: 4px; } .v2-board__ownership dt, .v2-board__ownership dd { margin: 0; padding: 10px 12px; min-height: 44px; display: flex; align-items: center; border-top: 1px solid var(--v2-border-soft); } .v2-board__ownership dt:first-of-type, .v2-board__ownership dd:first-of-type { border-top: 0; } .v2-board__ownership dt { font-size: 13px; font-weight: 500; color: var(--v2-text-secondary); } .v2-board__ownership dd { gap: 8px; font-size: 14px; min-width: 0; overflow-wrap: anywhere; } .v2-board__ownership select { min-height: 32px; max-width: 100%; padding: 0 34px 0 12px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-bg); color: var(--v2-text-primary); font: 500 13px/20px var(--v2-font-mono); } .v2-board__empty-owner, .v2-board__ownership .v2-board__lease-value { font: 500 12px/16px var(--v2-font-mono); } .v2-board__empty-owner { color: var(--v2-text-muted); } .v2-board__watchers-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; } .v2-board__watchers-head h3 { margin: 0; font-size: 13px; font-weight: 600; } .v2-board__watchers-count { font: 500 11px/16px var(--v2-font-mono); color: var(--v2-text-muted); } .v2-root button.v2-board__follow { margin-left: auto; min-height: 32px; padding: 0 10px; border: 1px solid var(--v2-border); border-radius: 4px; background: var(--v2-bg); color: var(--v2-text-secondary); font-size: 13px; font-weight: 600; } .v2-root button.v2-board__follow[aria-pressed="true"] { color: var(--v2-text-primary); } .v2-board__watcher-list { display: flex; flex-wrap: wrap; gap: 6px; } .v2-board__watcher { display: inline-flex; align-items: center; gap: 4px; min-height: 28px; max-width: 100%; padding: 0 8px 0 4px; border: 1px solid var(--v2-border-soft); border-radius: 4px; font-size: 12px; overflow-wrap: anywhere; } .v2-board .v2-board__member-avatar { width: 20px; height: 20px; min-width: 20px; border-radius: 4px; } .v2-board__watcher-hint, .v2-board__field small { margin: 8px 0 0; font-size: 12px; line-height: 16px; color: var(--v2-text-muted); } .v2-board__create-row { display: grid; grid-template-columns: minmax(0, 1fr) 140px; gap: 12px; } .v2-board__field input, .v2-board__field select { min-height: 40px; border-radius: 4px; } .v2-board__field select { font: 500 13px/20px var(--v2-font-mono); } @media (max-width: 760px) { .v2-board__col { flex: 0 0 78%; min-width: 250px; } .v2-root button.v2-board__card-move { min-height: 44px; padding: 0 14px; font-size: 13px; } .v2-board .v2-board__detail { position: absolute; inset: 44px 0 0; width: 100%; max-height: none; border-radius: 6px 6px 0 0; } .v2-board .v2-board__drawer { width: 100%; height: auto; border-radius: 6px 6px 0 0; } .v2-root button.v2-board__status-option { min-height: 44px; padding: 0 14px; } .v2-root button.v2-board__updates-toggle { min-height: 44px; } .v2-board__grab { display: block; width: 36px; height: 4px; border-radius: 2px; background: var(--v2-border-soft); margin: 8px auto 0; flex-shrink: 0; } .v2-board__detail .v2-modal__head { padding: 12px 16px 14px; } .v2-board__detail .v2-modal__body { padding: 14px 16px 24px; gap: 18px; } .v2-root .v2-board__detail button.v2-modal__close { width: 44px; height: 44px; } .v2-board__ownership { grid-template-columns: 104px minmax(0, 1fr); } .v2-board__ownership select, .v2-root button.v2-board__follow { min-height: 44px; } .v2-board__create-row { grid-template-columns: minmax(0, 1fr); } .v2-board__field input, .v2-board__field select { min-height: 44px; } } .v2-board__detail-meta .v2-inspector__pill { padding: 2px 6px; border: 1px solid var(--v2-border); border-radius: 4px; background: none; color: var(--v2-text-secondary); font: 500 11px/16px var(--v2-font-mono); } .v2-root button.v2-board__new, .v2-root button.v2-board__create-submit { background: var(--v2-text-primary); border-color: var(--v2-text-primary); color: var(--v2-bg); border-radius: 4px; } .v2-root button.v2-board__new:hover, .v2-root button.v2-board__create-submit:not(:disabled):hover { background: var(--v2-text-secondary); border-color: var(--v2-text-secondary); } .v2-board__owner-time { color: var(--v2-text-muted); } /* Public Privacy and Terms pages (TASK-530). Outside .v2-root, so no root-scoped selectors. */ /* .v2-root sets height:100vh and overflow:hidden; the legal pages must scroll, so override both (same as the landing). */ .v2-root.v2-legal { display: block; height: 100vh; overflow-y: auto; overflow-x: hidden; box-sizing: border-box; padding: 48px 24px; background: var(--v2-bg-subtle); color: var(--v2-text-primary); } .v2-legal__doc { max-width: 680px; margin: 0 auto; } .v2-legal__home { display: inline-block; margin: 0 0 24px; font-size: 14px; color: var(--v2-text-secondary); text-decoration: none; } .v2-legal__home:hover { text-decoration: underline; } .v2-legal__section a { color: var(--v2-text-primary); text-decoration: underline; } .v2-legal__title { font-size: 32px; font-weight: 600; line-height: 1.2; margin: 0 0 32px; } .v2-legal__section { margin-bottom: 28px; } .v2-legal__section h2 { font-size: 18px; font-weight: 600; margin: 0 0 8px; } .v2-legal__section p { font-size: 15px; line-height: 1.6; color: var(--v2-text-secondary); margin: 0 0 8px; }