diff --git a/src/client/components/agentGraph.tsx b/src/client/components/agentGraph.tsx index 422df2a..2aac7f3 100644 --- a/src/client/components/agentGraph.tsx +++ b/src/client/components/agentGraph.tsx @@ -249,6 +249,9 @@ function AgentNodeView(props: NodeViewProps): ReactElement { + (node.completed && !node.running ? ' lc-agent-done' : '') + (props.hovered ? ' lc-agent-hover' : '') + (node.isCurrent ? '' : ' lc-agent-clickable') + // The halo's hover/focus wash rides group variants on the node (the React + // hover state only drives the inspector; lc-agent-hover stays as a test anchor). + + ' group/agent' return ( { props.onHover(null) }} > {/* Halo carries the state: wash for self, breathing green while running, faint green for done. */} - + {segs.map(seg => ( ) => { props.onChange(ev.target.value) }} @@ -321,7 +321,7 @@ function ToolSchema(props: {
{jsonOpen ?
{schemaJson}
: null} @@ -820,7 +820,7 @@ export function makeContextBrowser( const open = openElem === key return (
- diff --git a/src/client/components/contextModal.tsx b/src/client/components/contextModal.tsx index e8e1080..981f195 100644 --- a/src/client/components/contextModal.tsx +++ b/src/client/components/contextModal.tsx @@ -116,7 +116,7 @@ export function makeContextModal(ctx: ClientCtx, kit: ViewKit): (props: ContextM
{ ev.stopPropagation() }}>
{t('tab')} - +
{data === null || head === null ? ( diff --git a/src/client/components/detailNote.tsx b/src/client/components/detailNote.tsx index c460254..191cd4d 100644 --- a/src/client/components/detailNote.tsx +++ b/src/client/components/detailNote.tsx @@ -30,7 +30,7 @@ export function makeDetailNote(kit: ViewKit): (props: { return (
{props.onRetry !== undefined - ? + ? : t('detail.loadFailed')}
) diff --git a/src/client/components/errorBoundary.tsx b/src/client/components/errorBoundary.tsx index b45752c..608dae4 100644 --- a/src/client/components/errorBoundary.tsx +++ b/src/client/components/errorBoundary.tsx @@ -29,7 +29,7 @@ export function makeErrorBoundary(t: Translate): ComponentType<{ children?: Reac {error.message}
diff --git a/src/client/components/fetchOnMiss.tsx b/src/client/components/fetchOnMiss.tsx index f123938..56fe594 100644 --- a/src/client/components/fetchOnMiss.tsx +++ b/src/client/components/fetchOnMiss.tsx @@ -77,7 +77,7 @@ export function fetchMissNote( if (state === 'absent') return t('browser.notInLog') if (state === 'failed') { return ( - ) diff --git a/src/client/components/fileCard.tsx b/src/client/components/fileCard.tsx index cff5a3a..322ca38 100644 --- a/src/client/components/fileCard.tsx +++ b/src/client/components/fileCard.tsx @@ -173,7 +173,7 @@ export function makeFileCard(kit: ViewKit, settings: ContextSettings): Component ))}
) => { setQuery(ev.target.value) }} @@ -183,9 +183,9 @@ export function makeFileCard(kit: ViewKit, settings: ContextSettings): Component {t('files.files', { n: activity.entries.length })} {activity.totals.added + activity.totals.removed > 0 ? ( /* The one styled tip of the card: it lives OUTSIDE the scrolling list, so the bubble never clips. */ - + - {t('files.deltaTip')} + {t('files.deltaTip')} ) : null} @@ -225,7 +225,7 @@ export function makeFileCard(kit: ViewKit, settings: ContextSettings): Component
diff --git a/src/client/components/requestDetail.tsx b/src/client/components/requestDetail.tsx index 269010d..9e65e0d 100644 --- a/src/client/components/requestDetail.tsx +++ b/src/client/components/requestDetail.tsx @@ -53,9 +53,9 @@ export function makeRequestDetail( }): ReactElement { const inner = ( <> - + {props.tag} - {props.tagTip} + {props.tagTip} {props.children} @@ -65,7 +65,7 @@ export function makeRequestDetail( const onLocate = props.onLocate const locate = (): void => { onLocate(node, props.isResponse) } return ( - ) @@ -160,7 +160,7 @@ export function makeRequestDetail( return ( diff --git a/src/client/components/settingsCard.tsx b/src/client/components/settingsCard.tsx index 944fce1..54b2a30 100644 --- a/src/client/components/settingsCard.tsx +++ b/src/client/components/settingsCard.tsx @@ -44,7 +44,7 @@ function PrefRow(props: PrefRowProps): ReactElement { anchor={( +
{t('gate.body', { minimum: props.minimum })}
@@ -66,7 +66,7 @@ export function makeUpgradeGate(kit: ViewKit): (props: UpgradeGateProps) => Reac
- +
diff --git a/src/client/styles/agentGraph.css b/src/client/styles/agentGraph.css index b71ba6b..ead6c6d 100644 --- a/src/client/styles/agentGraph.css +++ b/src/client/styles/agentGraph.css @@ -16,9 +16,9 @@ @keyframes lc-agent-flow { to { stroke-dashoffset: -9; } } .lc-agent-node { outline: none; } .lc-agent-clickable { cursor: pointer; } -/* The halo carries node state: hover wash, brand tint for self, breathing green while running, a faint green rest for done. */ +/* The halo carries node state: the hover/focus wash rides `group-hover/agent`/`group-focus-visible/agent` + variants in agentGraph.tsx, brand tint for self, breathing green while running, a faint green rest for done. */ .lc-agent-halo { fill: transparent; transition: fill var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-agent-hover .lc-agent-halo, .lc-agent-node:focus-visible .lc-agent-halo { fill: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2)); } .lc-agent-self .lc-agent-halo { fill: var(--dsw-alias-bg-layer-2); } .lc-agent-running .lc-agent-halo { fill: color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent); animation: lc-agent-glow 1.8s ease-in-out infinite; } .lc-agent-done .lc-agent-halo { fill: color-mix(in srgb, var(--dsw-alias-state-success-primary) 7%, transparent); } diff --git a/src/client/styles/attachments.css b/src/client/styles/attachments.css index 15a8f58..5111f4c 100644 --- a/src/client/styles/attachments.css +++ b/src/client/styles/attachments.css @@ -1,7 +1,6 @@ /* Attachment grids and the image lightbox (browser.tsx inline grid + images.tsx lightbox). */ .lc-att-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; padding: 8px 10px; } .lc-att-item { display: flex; gap: 8px; align-items: center; min-width: 0; width: 100%; box-sizing: border-box; padding: 6px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; background: transparent; font: inherit; text-align: left; cursor: pointer; transition: border-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out), background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-att-item:hover { border-color: var(--dsw-alias-label-dimmed); background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2)); } .lc-att-thumb { width: 64px; height: 64px; flex: none; padding: 0; display: flex; align-items: center; justify-content: center; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; overflow: hidden; background: var(--dsw-alias-bg-layer-1); } .lc-att-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; } .lc-att-ph, .lc-att-err { font-size: 10px; color: var(--dsw-alias-label-secondary); text-align: center; padding: 2px; } diff --git a/src/client/styles/base.css b/src/client/styles/base.css index 36e9fe8..836e064 100644 --- a/src/client/styles/base.css +++ b/src/client/styles/base.css @@ -78,9 +78,10 @@ .lc-gran-on .lc-kind-n { opacity: 0.85; } /* Shared tooltip-bubble chrome: pair `.lc-tip` with the owner's own tip class, - then position locally (top/bottom anchor, width cap, whitespace, reveal rule). - The component sheets carry the four shippers (.lc-stat-tip / .lc-brief-tip / - .lc-fa-meta-tip / .lc-bar-tip); a new tip never re-declares this chrome. + then position locally (top/bottom anchor, width cap, whitespace); the reveal + rides a `group-hover/tip` variant on the owner. The component sheets carry + the four shippers (.lc-stat-tip / .lc-brief-tip / .lc-fa-meta-tip / .lc-bar-tip); + a new tip never re-declares this chrome. */ .lc-tip { position: absolute; z-index: 6; width: max-content; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 6px 10px; font-size: 12px; color: var(--dsw-alias-label-primary); box-shadow: var(--dsw-shadow-lv3, 0 2px 8px rgba(0, 0, 0, 0.18)); pointer-events: none; opacity: 0; transition: opacity var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } .lc-events, .lc-fa-list { display: flex; flex-direction: column; gap: 2px; height: 320px; overflow-y: auto; } @@ -127,7 +128,6 @@ .lc-error { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 40px 16px; } .lc-error-msg { font-family: var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 12px; color: var(--dsw-alias-state-error-primary); background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 4px 8px; max-width: 100%; overflow-wrap: anywhere; } .lc-error-retry { border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); font: inherit; font-size: 12px; padding: 4px 14px; border-radius: 6px; cursor: pointer; transition: border-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-error-retry:hover { border-color: var(--dsw-alias-label-primary); } .lc-foot { color: var(--dsw-alias-label-secondary); font-size: 12px; margin-top: 4px; } [data-conversation-scroll]:has(.lc-root) > [data-composer-seat]:not(:has([data-approval-key], [data-question-key], [data-plan-review-key])) { display: none; } /* diff --git a/src/client/styles/browser.css b/src/client/styles/browser.css index 5befa30..33c604f 100644 --- a/src/client/styles/browser.css +++ b/src/client/styles/browser.css @@ -14,12 +14,10 @@ .lc-br-meta .lc-est { margin-left: auto; } .lc-br-note { margin-top: 8px; color: var(--dsw-alias-label-secondary); font-size: 12px; } .lc-br-retry { border: 0; background: transparent; padding: 0; color: var(--dsw-alias-brand-primary); font: inherit; font-size: 12px; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; transition: filter var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-br-retry:hover { filter: brightness(1.15); } .lc-br-cats { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; } .lc-br-cat { border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; background: var(--dsw-alias-bg-layer-2); overflow: hidden; } .lc-br-cat-empty { opacity: 0.55; } .lc-br-cat-row { display: flex; align-items: center; gap: 8px; width: 100%; border: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; padding: 7px 10px; cursor: pointer; text-align: left; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-br-cat-row:hover { background: var(--dsw-alias-interactive-bg-hover); } /* Current-composition hover echo: the category row lit by the shared hover link looks hovered — same tint as a physical hover, plus a ring on its color dot. */ @@ -48,7 +46,6 @@ .lc-br-elem { border-radius: 6px; } .lc-br-elem-on { background: var(--dsw-alias-interactive-bg-active); } .lc-br-elem-row { display: flex; align-items: center; gap: 8px; width: 100%; border: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; font-size: 12px; padding: 5px 6px; cursor: pointer; text-align: left; border-radius: 6px; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-br-elem-row:hover { background: var(--dsw-alias-interactive-bg-hover); } /* Failed tool result: the chat's red run-state dot (6px core on a 10px halo) leads the collapsed row, so the failure scans without expanding. */ .lc-br-err-dot { flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--dsw-alias-state-error-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent); } diff --git a/src/client/styles/detailSections.css b/src/client/styles/detailSections.css index 37a6363..d59faab 100644 --- a/src/client/styles/detailSections.css +++ b/src/client/styles/detailSections.css @@ -48,7 +48,6 @@ .lc-ts-arg-val { color: var(--dsw-alias-label-primary); font-family: var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 12px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; max-height: 200px; overflow-y: auto; scrollbar-width: thin; } .lc-ts-json { display: flex; flex-direction: column; gap: 4px; } .lc-ts-json-toggle { align-self: flex-start; border: 0; background: transparent; color: var(--dsw-alias-label-secondary); font: inherit; font-size: 11px; padding: 0; cursor: pointer; transition: color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-ts-json-toggle:hover { color: var(--dsw-alias-label-primary); text-decoration: underline; } .lc-rich-seg { margin-left: auto; display: flex; gap: 2px; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; padding: 1px; } .lc-rich-seg-btn { border: 0; background: transparent; color: var(--dsw-alias-label-secondary); font-size: 11px; line-height: 1; padding: 3px 8px; border-radius: 5px; cursor: pointer; font-family: inherit; transition: color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } .lc-rich-seg-btn:hover { color: var(--dsw-alias-label-primary); } diff --git a/src/client/styles/fileCard.css b/src/client/styles/fileCard.css index 0fbd37c..e9aa386 100644 --- a/src/client/styles/fileCard.css +++ b/src/client/styles/fileCard.css @@ -8,19 +8,16 @@ .lc-fa-ctl .lc-gran { margin-left: 0; } .lc-fa-n { margin-left: 4px; font-weight: 700; opacity: 0.75; } .lc-fa-search, .lc-br-tool-search { flex: 1; min-width: 80px; font: inherit; font-size: 12px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; padding: 3px 8px; outline: none; } -.lc-fa-search:focus, .lc-br-tool-search:focus { border-color: var(--dsw-alias-label-dimmed); } .lc-fa-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 6px; color: var(--dsw-alias-label-secondary); font-size: 12px; } /* The sort toggle rides the meta strip's right edge — the shared .lc-gran's own auto margin does the push. */ .lc-fa-meta .lc-fa-sort { flex: none; } /* The aggregate delta pill carries the card's one styled tip (the shared `.lc-tip` chrome) — it sits outside the scrolling list, so the bubble never clips. */ .lc-fa-meta-delta { position: relative; } .lc-fa-meta-tip { top: calc(100% + 6px); left: 0; max-width: 260px; white-space: normal; line-height: 1.5; } -.lc-fa-meta-delta:hover .lc-fa-meta-tip { opacity: 1; } /* An expanded file reads as one contained card: layer-2 fill inside a hairline frame. */ .lc-fa-item { border: 1px solid transparent; border-radius: 8px; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out), border-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } .lc-fa-item-on { background: var(--dsw-alias-bg-layer-2); border-color: var(--dsw-alias-border-l2); } .lc-fa-row { display: flex; align-items: center; gap: 7px; width: 100%; border: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; font-size: 12px; padding: 6px 8px; cursor: pointer; text-align: left; border-radius: 7px; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-fa-row:hover { background: var(--dsw-alias-interactive-bg-hover); } .lc-fa-form { flex: none; width: 20px; height: 14px; display: flex; align-items: center; justify-content: center; font-size: 11px; opacity: 0.85; } .lc-fa-lang { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 13px; padding: 0 2px; border-radius: 4px; font-size: 8px; font-weight: 700; line-height: 1; } /* The chevron sits close to the icon: only half the row gap stays visible. */ @@ -42,7 +39,6 @@ .lc-fa-ctl .lc-gran { flex-wrap: wrap; } } .lc-fa-file { cursor: pointer; } -.lc-fa-file:hover { text-decoration: underline; } .lc-fa-path em { font-style: normal; color: var(--dsw-alias-label-secondary); } /* Per-purpose count badges: pill chips, one fixed tint per purpose (read = brand, write = success, search = warn). */ .lc-fa-badge { flex: none; display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; padding: 1px 7px; border-radius: 999px; white-space: nowrap; } @@ -65,7 +61,6 @@ .lc-fa-ops { margin: 0 8px 8px 15px; padding: 2px 0 2px 10px; border-left: 2px solid var(--dsw-alias-border-l1); display: flex; flex-direction: column; gap: 1px; } .lc-fa-op { display: flex; align-items: center; gap: 8px; min-width: 0; border: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; font-size: 11px; padding: 3px 6px; text-align: left; border-radius: 5px; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } .lc-fa-op-link { cursor: pointer; } -.lc-fa-op-link:hover { background: var(--dsw-alias-interactive-bg-hover); } .lc-fa-op-time { flex: none; margin-left: auto; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; } .lc-fa-op-tool { flex: none; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; padding: 0 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l1); color: var(--dsw-alias-label-secondary); } .lc-fa-op-detail { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary); } diff --git a/src/client/styles/jump.css b/src/client/styles/jump.css index c4b5dfa..d92a5df 100644 --- a/src/client/styles/jump.css +++ b/src/client/styles/jump.css @@ -2,4 +2,3 @@ /* The chat action-row jump button — mirrors the harness MessageIconActions `.action` chrome so it sits flush beside the shipped icons. */ .lc-jump { display: inline-flex; align-items: center; justify-content: center; width: calc(28px + var(--dsh-content-font-delta, 0px)); height: calc(28px + var(--dsh-content-font-delta, 0px)); padding: 6px; border: 0; border-radius: 28px; background: transparent; color: var(--dsw-alias-label-tertiary); cursor: pointer; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out), color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } .lc-jump svg { width: calc(16px + var(--dsh-content-font-delta, 0px)); height: calc(16px + var(--dsh-content-font-delta, 0px)); } -.lc-jump:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-secondary); } diff --git a/src/client/styles/modal.css b/src/client/styles/modal.css index 74e313b..419872b 100644 --- a/src/client/styles/modal.css +++ b/src/client/styles/modal.css @@ -6,7 +6,6 @@ .lc-modal-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 12px; } .lc-modal-title { font-weight: 600; font-size: 14px; } .lc-modal-close { margin-left: auto; border: 0; background: transparent; color: var(--dsw-alias-label-secondary); font-size: 18px; line-height: 1; padding: 2px 6px; border-radius: 6px; cursor: pointer; font-family: inherit; transition: color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out), background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-modal-close:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); } /* ---- the baseline-gate dialog (upgradeGate.tsx): narrower card, version rows, one primary action ---- */ .lc-gate-card { width: min(440px, calc(100vw - 48px)); } @@ -19,4 +18,3 @@ .lc-gate-or-newer { margin-left: 6px; font-family: inherit; font-weight: 400; font-size: 11px; color: var(--dsw-alias-label-secondary); } .lc-gate-actions { display: flex; justify-content: flex-end; margin-top: 16px; } .lc-gate-ok { border: 0; border-radius: 6px; padding: 6px 16px; font-size: 12px; font-family: inherit; cursor: pointer; background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-foreground); transition: filter var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-gate-ok:hover { filter: brightness(1.1); } diff --git a/src/client/styles/requestDetail.css b/src/client/styles/requestDetail.css index e823bc6..f55f00d 100644 --- a/src/client/styles/requestDetail.css +++ b/src/client/styles/requestDetail.css @@ -24,12 +24,10 @@ .lc-brief-row { display: flex; align-items: center; gap: 8px; min-width: 0; padding: 3px 6px; margin-left: -6px; margin-right: -6px; border-radius: 6px; border: 0; background: transparent; font-family: inherit; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-primary); text-align: left; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } /* The link class marks a hoverable ROW (buttons and the chip-carrying inputs row alike); the pointer cursor belongs only to the actual click targets — button rows and individual chips. */ -.lc-brief-row-link:hover { background: var(--dsw-alias-interactive-bg-hover); } button.lc-brief-row-link { cursor: pointer; } .lc-brief-tag { flex: none; box-sizing: border-box; min-width: 56px; text-align: center; font-size: 11px; padding: 0 6px; border-radius: 4px; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); color: var(--dsw-alias-label-secondary); position: relative; } -/* The tag's explanation bubble — the shared `.lc-tip` chrome: instant styled reveal on tag hover, never intercepts the pointer. */ +/* The tag's explanation bubble — the shared `.lc-tip` chrome: instant styled reveal on tag hover (a `group-hover/tip` variant), never intercepts the pointer. */ .lc-brief-tip { bottom: calc(100% + 6px); left: 0; max-width: 240px; white-space: normal; text-align: left; line-height: 1.5; font-weight: 400; } -.lc-brief-tag:hover .lc-brief-tip { opacity: 1; } .lc-brief-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* The empty-state In row's placeholder: same anatomy as the preview text, muted. */ .lc-brief-empty { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary); } @@ -42,7 +40,6 @@ button.lc-brief-row-link { cursor: pointer; } .lc-brief-chip-tag { flex: none; max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; padding: 0 6px; border-radius: 4px; background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l1); color: var(--dsw-alias-label-secondary); } .lc-brief-chip-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .lc-brief-chip-link { cursor: pointer; } -.lc-brief-chip-link:hover { background: var(--dsw-alias-interactive-bg-hover); } .lc-brief-more { flex: none; font-size: 11px; color: var(--dsw-alias-label-secondary); } .lc-detail-row { display: flex; align-items: center; gap: 8px; border-radius: 4px; /* Padding + matching negative margin: the highlight paints past the text while the layout stays put. */ padding: 1px 4px; margin: -1px -4px; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } /* Category hover-link: the shared hover lights the matching detail row — same pairing as the legend chips and the diff --git a/src/client/styles/settings.css b/src/client/styles/settings.css index 18ba4ef..95489fd 100644 --- a/src/client/styles/settings.css +++ b/src/client/styles/settings.css @@ -12,6 +12,4 @@ .lc-settings-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; } .lc-settings-label { flex: 1; min-width: 0; font-size: 14px; color: var(--dsw-alias-label-primary); } .lc-settings-select { display: inline-flex; align-items: center; gap: 12px; height: 36px; padding: 0 14px; border: none; border-radius: 18px; background: var(--dsw-alias-bg-module-platform); font: inherit; font-size: 14px; line-height: 22px; color: var(--dsw-alias-label-primary); cursor: pointer; transition: background-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-settings-select:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); } -.lc-settings-select:disabled { opacity: .5; cursor: default; } .lc-settings-note { color: var(--dsw-alias-label-tertiary); font-size: 12px; line-height: 1.5; margin: 12px 0 4px; } diff --git a/src/client/styles/stats.css b/src/client/styles/stats.css index 8942e58..62b8dd6 100644 --- a/src/client/styles/stats.css +++ b/src/client/styles/stats.css @@ -16,13 +16,11 @@ .lc-stat-value { color: var(--dsw-alias-label-primary); font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center; } .lc-stat-sub { color: var(--dsw-alias-label-secondary); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* - Stats cell tooltip (cost cell): styled DOM bubble because native `title` can't hold the multi-row price breakdown; a '?' signals the affordance and hovering anywhere on the cell reveals the bubble below (the cell is the tip's position frame). Chrome rides the shared `.lc-tip`. + Stats cell tooltip (cost cell): styled DOM bubble because native `title` can't hold the multi-row price breakdown; a '?' signals the affordance and hovering anywhere on the cell reveals the bubble below (the cell is the tip's position frame). Chrome rides the shared `.lc-tip`; the reveal and the badge's brighten ride `group-hover/tip` variants (`group/tip` on the cell). */ .lc-stat-tipped { position: relative; } .lc-stat-q { display: inline-block; margin-left: 4px; width: 11px; height: 11px; line-height: 11px; border-radius: 50%; text-align: center; font-size: 9px; font-weight: 700; font-style: normal; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l2); cursor: help; transition: color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out), border-color var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); } -.lc-stat-tipped:hover .lc-stat-q { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-label-primary); } .lc-stat-tip { top: calc(100% + 6px); left: 0; max-width: 280px; line-height: 1.5; font-weight: 400; } -.lc-stat-tipped:hover .lc-stat-tip { opacity: 1; } .lc-stat-tip-prices { display: block; margin-top: 5px; border-top: 1px dashed var(--dsw-alias-border-l1); padding-top: 5px; } .lc-stat-tip-head { display: block; font-weight: 600; } .lc-stat-tip-row { display: block; margin-top: 2px; } @@ -92,9 +90,7 @@ /* The settings-entry row is a button wearing the link-row chrome — reset the button chrome the shared row style doesn't cover. */ .lc-pi-row-btn { appearance: none; border: 0; background: none; font: inherit; color: inherit; text-align: left; padding: 0; cursor: pointer; width: 100%; } .lc-pi-row { display: flex; flex-direction: row; justify-content: space-between; align-items: baseline; gap: 12px; min-width: 0; text-decoration: none; color: inherit; } -.lc-pi-row:hover .lc-pi-value { text-decoration: underline; } .lc-pi-hint { text-decoration: none; } -.lc-pi-hint:hover { text-decoration: underline; } .lc-pi-update { color: var(--dsw-alias-state-warn-primary); font-size: 11px; margin-left: 6px; white-space: nowrap; } .lc-pi-label { flex: none; color: var(--dsw-alias-label-secondary); font-size: 11px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* diff --git a/src/client/styles/tailwind.css b/src/client/styles/tailwind.css index 6503f79..5ec2897 100644 --- a/src/client/styles/tailwind.css +++ b/src/client/styles/tailwind.css @@ -1,10 +1,13 @@ /* - * Tailwind entry: compiles (tsdown.config.ts, @tailwindcss/node) the layout - * utilities carried by the plugin's JSX class lists — box layout, flex/grid, - * spacing, sizing, positioning, overflow, and the @container responsive - * variants. The sibling sheets keep everything Tailwind does not own here: - * the harness's `--dsw-*` color/typography chrome, hover/focus states, - * contextual selectors, animations. + * Tailwind entry: compiles (tsdown.config.ts, @tailwindcss/node) the utilities + * carried by the plugin's JSX class lists — box layout, flex/grid, spacing, + * sizing, positioning, overflow, the @container responsive variants, and the + * pure `:hover`/`:focus` pseudo-state styling (hover/focus/group-hover + * variants; Tailwind media-guards hover behind `(hover: hover)`). The sibling + * sheets keep everything the variants cannot own here: the harness's + * `--dsw-*` color/typography chrome, the JS-state class systems (the lit/dim/ + * selected markers, several of which double as test anchors and DOM query + * hooks), their contextual overrides, and animations. * * Deliberate deviations from a stock Tailwind setup, all for cohabitation * with the harness host page: diff --git a/src/client/styles/trendChart.css b/src/client/styles/trendChart.css index 039dd10..d198738 100644 --- a/src/client/styles/trendChart.css +++ b/src/client/styles/trendChart.css @@ -45,7 +45,6 @@ .lc-chart-tip { position: absolute; bottom: calc(100% + 4px); left: 0; z-index: 5; display: flex; flex-direction: column; gap: 2px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 3px 8px; font-size: 12px; color: var(--dsw-alias-label-primary); box-shadow: 0 2px 8px rgba(0,0,0,0.18); pointer-events: none; } /* The metric row reads secondary to the identity row. */ .lc-chart-tip span + span { color: var(--dsw-alias-label-secondary); } -.lc-bar:hover { background: var(--dsw-alias-bg-layer-2); } /* Hovering previews a bar with a thin dashed frame; a CLICKED (locked) bar must always show the strong solid frame, so the selected rule is diff --git a/tests/client/components/browser.spec.ts b/tests/client/components/browser.spec.ts index 06096c6..a1228fc 100644 --- a/tests/client/components/browser.spec.ts +++ b/tests/client/components/browser.spec.ts @@ -879,7 +879,7 @@ describe('ContextBrowser tool schemas', () => { assert.equal(text(query(rows[0], '.lc-br-preview')), 'write', 'tool name leads') const chip = chips[0] as HTMLElement assert.equal(chip.previousElementSibling, query(rows[0], '.lc-br-preview'), 'plugin chip sits right after the tool name') - assert.equal(chip.parentElement!.className, 'lc-br-elem-row', 'plugin chip is a single frame, a direct row child') + assert.ok(chip.parentElement!.classList.contains('lc-br-elem-row'), 'plugin chip is a single frame, a direct row child') assert.equal(queryAll(chip, '.lc-br-tag').length, 0, 'no nested tag wrapper') await m.unmount() })