diff --git a/codestory-ui/index.html b/codestory-ui/index.html index ab85726..9705c99 100644 --- a/codestory-ui/index.html +++ b/codestory-ui/index.html @@ -7,7 +7,7 @@ diff --git a/codestory-ui/package-lock.json b/codestory-ui/package-lock.json index 916ce12..abf4929 100644 --- a/codestory-ui/package-lock.json +++ b/codestory-ui/package-lock.json @@ -12,6 +12,7 @@ "@monaco-editor/react": "4.7.0", "@xyflow/react": "12.10.1", "html-to-image": "^1.11.13", + "lucide-react": "^0.575.0", "mermaid": "11.12.3", "monaco-editor": "0.55.1", "react": "19.2.4", @@ -4002,6 +4003,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.575.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.575.0.tgz", + "integrity": "sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", diff --git a/codestory-ui/package.json b/codestory-ui/package.json index 88e9faa..0d8a546 100644 --- a/codestory-ui/package.json +++ b/codestory-ui/package.json @@ -26,6 +26,7 @@ "@monaco-editor/react": "4.7.0", "@xyflow/react": "12.10.1", "html-to-image": "^1.11.13", + "lucide-react": "^0.575.0", "mermaid": "11.12.3", "monaco-editor": "0.55.1", "react": "19.2.4", diff --git a/codestory-ui/src/App.tsx b/codestory-ui/src/App.tsx index 2f60b6a..26ab088 100644 --- a/codestory-ui/src/App.tsx +++ b/codestory-ui/src/App.tsx @@ -8,7 +8,6 @@ import { toMonacoModelPath, type AgentConnectionState, } from "./app/layoutPersistence"; -import { loadFeatureFlags, saveFeatureFlags, type FeatureFlagState } from "./app/featureFlags"; import { trackAnalyticsEvent } from "./app/analytics"; import { UI_CONTRACT, UI_LAYOUT_SCHEMA_STORAGE_KEY } from "./app/uiContract"; import type { PendingSymbolFocus } from "./app/types"; @@ -107,7 +106,6 @@ export default function App() { const [bookmarkSeed, setBookmarkSeed] = useState<{ nodeId: string; label: string } | null>(null); const [activeSection, setActiveSection] = useState("investigate"); const [commandPaletteOpen, setCommandPaletteOpen] = useState(false); - const [featureFlags, setFeatureFlags] = useState(() => loadFeatureFlags()); const [investigateMode, setInvestigateMode] = useState(() => { if (typeof window === "undefined") { return "graph"; @@ -164,10 +162,6 @@ export default function App() { window.localStorage.setItem(UI_LAYOUT_SCHEMA_STORAGE_KEY, String(UI_CONTRACT.schemaVersion)); }, [investigateMode]); - useEffect(() => { - saveFeatureFlags(featureFlags); - }, [featureFlags]); - useEffect(() => { const previous = previousIndexProgressRef.current; if (previous !== null && indexProgress === null) { @@ -591,13 +585,6 @@ export default function App() { })); }, []); - const updateFeatureFlag = useCallback((flag: keyof FeatureFlagState, value: boolean) => { - setFeatureFlags((previous) => ({ - ...previous, - [flag]: value, - })); - }, []); - const refreshSpaces = useCallback(() => { setSpaces(listSpaces()); }, []); @@ -848,29 +835,16 @@ export default function App() { label: "Save Investigation Space", detail: "Store current prompt and focus for reuse", keywords: ["space", "save", "library"], - disabled: !featureFlags.spacesLibrary, run: () => invokeCommand("save-space", () => { createSpaceFromCurrentContext("", ""); setActiveSection("library"); }), }, - { - id: "toggle-ux-reset", - label: featureFlags.uxResetV2 ? "Disable UX Reset" : "Enable UX Reset", - detail: "Rollback switch for staged rollout", - keywords: ["feature flag", "rollback", "shell"], - run: () => - invokeCommand("toggle-ux-reset", () => { - updateFeatureFlag("uxResetV2", !featureFlags.uxResetV2); - }), - }, ], [ activeSection, createSpaceFromCurrentContext, - featureFlags.spacesLibrary, - featureFlags.uxResetV2, focusGraphSearchInput, handleInvestigateModeChange, handlePrompt, @@ -883,7 +857,6 @@ export default function App() { prompt, runIndexFromUi, trailDisabledReason, - updateFeatureFlag, ], ); @@ -1034,14 +1007,6 @@ export default function App() { /> ); - const legacyWorkspaceView = ( -
- {responsePaneView} - {graphPaneView} - {codePaneView} -
- ); - const focusedPane = investigateMode === "graph" ? graphPaneView @@ -1051,31 +1016,29 @@ export default function App() { const focusedWorkspaceView = (
- {featureFlags.onboardingStarter ? ( - 0} - askedFirstQuestion={askedFirstQuestion} - inspectedSource={inspectedSource} - onOpenProject={openProjectFromUi} - onRunIndex={runRecommendedIndex} - onSeedQuestion={seedFirstQuestion} - onInspectSource={jumpToSourceInspection} - onPrimaryAction={(action) => { - trackAnalyticsEvent( - "starter_card_cta_clicked", - { - action, - }, - { - projectPath, - }, - ); - }} - /> - ) : null} + 0} + askedFirstQuestion={askedFirstQuestion} + inspectedSource={inspectedSource} + onOpenProject={openProjectFromUi} + onRunIndex={runRecommendedIndex} + onSeedQuestion={seedFirstQuestion} + onInspectSource={jumpToSourceInspection} + onPrimaryAction={(action) => { + trackAnalyticsEvent( + "starter_card_cta_clicked", + { + action, + }, + { + projectPath, + }, + ); + }} + />
Save Space @@ -1108,12 +1070,8 @@ export default function App() {
); - const workspaceView = featureFlags.singlePaneInvestigate - ? focusedWorkspaceView - : legacyWorkspaceView; - const sectionContent: Partial> = { - library: featureFlags.spacesLibrary ? ( + library: ( - ) : ( -
-

Spaces Disabled

-

Enable spaces in Settings to save and reopen investigations.

-
), - settings: , + settings: , }; return ( @@ -1147,16 +1100,12 @@ export default function App() { - {featureFlags.uxResetV2 ? ( - - ) : ( - legacyWorkspaceView - )} + { - return typeof value === "object" && value !== null; -} - -export function normalizeFeatureFlags(raw: unknown): FeatureFlagState { - if (!isRecord(raw)) { - return DEFAULT_FLAGS; - } - const legacyModernShell = - typeof raw.modernShell === "boolean" ? raw.modernShell : DEFAULT_FLAGS.uxResetV2; - const legacyOnboarding = - typeof raw.onboarding === "boolean" ? raw.onboarding : DEFAULT_FLAGS.onboardingStarter; - - return { - uxResetV2: typeof raw.uxResetV2 === "boolean" ? raw.uxResetV2 : legacyModernShell, - onboardingStarter: - typeof raw.onboardingStarter === "boolean" ? raw.onboardingStarter : legacyOnboarding, - singlePaneInvestigate: - typeof raw.singlePaneInvestigate === "boolean" - ? raw.singlePaneInvestigate - : DEFAULT_FLAGS.singlePaneInvestigate, - spacesLibrary: - typeof raw.spacesLibrary === "boolean" ? raw.spacesLibrary : DEFAULT_FLAGS.spacesLibrary, - }; -} - -export function loadFeatureFlags(): FeatureFlagState { - const storage = getStorage(); - if (!storage) { - return DEFAULT_FLAGS; - } - const raw = storage.getItem(FEATURE_FLAGS_STORAGE_KEY); - if (!raw) { - return DEFAULT_FLAGS; - } - try { - const parsed = JSON.parse(raw) as unknown; - return normalizeFeatureFlags(parsed); - } catch { - return DEFAULT_FLAGS; - } -} - -export function saveFeatureFlags(flags: FeatureFlagState): void { - const storage = getStorage(); - if (!storage) { - return; - } - storage.setItem(FEATURE_FLAGS_STORAGE_KEY, JSON.stringify(flags)); -} diff --git a/codestory-ui/src/app/useEditorDecorations.ts b/codestory-ui/src/app/useEditorDecorations.ts index b81d5c5..3817311 100644 --- a/codestory-ui/src/app/useEditorDecorations.ts +++ b/codestory-ui/src/app/useEditorDecorations.ts @@ -3,6 +3,7 @@ import { type Monaco, type OnMount } from "@monaco-editor/react"; import type { CodeEdgeContext } from "../components/CodePane"; import type { NodeDetailsDto, SourceOccurrenceDto } from "../generated/api"; +import { GRAPH_THEME } from "../theme/tokens"; type UseEditorDecorationsArgs = { saveCurrentFile: () => Promise; @@ -120,7 +121,7 @@ export function useEditorDecorations({ isWholeLine: true, className: "monaco-focus-line", overviewRuler: { - color: "#f0b42988", + color: GRAPH_THEME.editorOverview, position: monaco.editor.OverviewRulerLane.Center, }, }, diff --git a/codestory-ui/src/components/InvestigateFocusSwitcher.tsx b/codestory-ui/src/components/InvestigateFocusSwitcher.tsx index a8da06f..b7af6cb 100644 --- a/codestory-ui/src/components/InvestigateFocusSwitcher.tsx +++ b/codestory-ui/src/components/InvestigateFocusSwitcher.tsx @@ -3,6 +3,10 @@ import { investigateFocusModeLabel, type InvestigateFocusMode, } from "../layout/layoutPresets"; +import { Bolt, Code2, Orbit } from "lucide-react"; +import type { ReactNode } from "react"; + +import { Button } from "../ui/primitives"; type InvestigateFocusSwitcherProps = { mode: InvestigateFocusMode; @@ -10,23 +14,29 @@ type InvestigateFocusSwitcherProps = { }; export function InvestigateFocusSwitcher({ mode, onModeChange }: InvestigateFocusSwitcherProps) { + const modeIcons: Record = { + ask: , + graph: , + code: , + }; return (
{INVESTIGATE_FOCUS_MODES.map((candidate) => { const isActive = candidate === mode; return ( - + ); })}
diff --git a/codestory-ui/src/components/StatusStrip.tsx b/codestory-ui/src/components/StatusStrip.tsx index ddbd9ed..62c376a 100644 --- a/codestory-ui/src/components/StatusStrip.tsx +++ b/codestory-ui/src/components/StatusStrip.tsx @@ -7,11 +7,11 @@ export function StatusStrip({ status, indexProgress }: StatusStripProps) { return (
{status} - {indexProgress && ( + {indexProgress ? ( Indexing {indexProgress.current}/{indexProgress.total} - )} + ) : null}
); } diff --git a/codestory-ui/src/components/TopBar.tsx b/codestory-ui/src/components/TopBar.tsx index 2a1b57a..b7b0487 100644 --- a/codestory-ui/src/components/TopBar.tsx +++ b/codestory-ui/src/components/TopBar.tsx @@ -1,4 +1,7 @@ import type { ChangeEvent } from "react"; +import { FolderOpen, RefreshCcw, ScanSearch } from "lucide-react"; + +import { Button } from "../ui/primitives"; type IndexMode = "Full" | "Incremental"; @@ -37,15 +40,28 @@ export function TopBar({ placeholder="Project path" aria-label="Project path" /> - - + - + +
); diff --git a/codestory-ui/src/features/onboarding/StarterCard.tsx b/codestory-ui/src/features/onboarding/StarterCard.tsx index eecede1..c6b73ff 100644 --- a/codestory-ui/src/features/onboarding/StarterCard.tsx +++ b/codestory-ui/src/features/onboarding/StarterCard.tsx @@ -1,4 +1,7 @@ import { useEffect, useMemo, useState } from "react"; +import { Sparkles } from "lucide-react"; + +import { Badge, Button, Card } from "../../ui/primitives"; type StarterCardProps = { projectPath: string; @@ -112,27 +115,28 @@ export function StarterCard({ if (dismissed) { return ( -
+

Starter card dismissed.

- -
+ + ); } return ( -
+
-

Start Here

- +
- + Project - - + + Index - - + Ready - +
@@ -167,8 +171,8 @@ export function StarterCard({
{nextStep.run ? ( - + ) : null} - + {helpOpen ? (

Use `Ctrl+K` for quick actions and switch focus modes to keep context clear.

) : null} -
+ ); } diff --git a/codestory-ui/src/features/settings/SettingsPage.tsx b/codestory-ui/src/features/settings/SettingsPage.tsx index 90a3a95..a52379d 100644 --- a/codestory-ui/src/features/settings/SettingsPage.tsx +++ b/codestory-ui/src/features/settings/SettingsPage.tsx @@ -1,60 +1,58 @@ -import type { FeatureFlagState } from "../../app/featureFlags"; +import { Keyboard, Paintbrush2, Radar } from "lucide-react"; -type SettingsPageProps = { - featureFlags: FeatureFlagState; - onUpdateFlag: (flag: keyof FeatureFlagState, value: boolean) => void; -}; +import { Badge, Card } from "../../ui/primitives"; -export function SettingsPage({ featureFlags, onUpdateFlag }: SettingsPageProps) { +export function SettingsPage() { return (
-

Settings

-

Global preferences only. Workflow controls stay in contextual drawers.

+

+ Settings +

+

Playful Geometric theme is now the default experience for every workspace.

- + +

Visual System

+

+ Design tokens, typography, motion, and graph chrome are centralized in `src/theme/`. +

+ Active +
- + +

Workspace Mode

+

+ Single-pane Investigate and Spaces Library are always enabled in the canonical shell. +

+ Canonical +
- - - + +

Accessibility

+

+ Focus rings, high-contrast states, large tap targets, and reduced-motion fallbacks are + enforced by default. +

+ WCAG-minded +
-
-

Keyboard

+ +

+ Keyboard +

`Ctrl+K` opens command palette for fast actions.

-
+

`Ctrl+U` opens trail settings while focused in graph view.

+ + + +

+ Graph Semantics +

+

Edge colors remain semantically distinct while adopting playful tokens.

+
); } diff --git a/codestory-ui/src/features/spaces/SpacesPanel.tsx b/codestory-ui/src/features/spaces/SpacesPanel.tsx index d1fcaf7..a349124 100644 --- a/codestory-ui/src/features/spaces/SpacesPanel.tsx +++ b/codestory-ui/src/features/spaces/SpacesPanel.tsx @@ -1,6 +1,8 @@ import { useMemo, useState } from "react"; +import { LibraryBig, Search, Trash2 } from "lucide-react"; import type { InvestigationSpace } from "./types"; +import { Button, Card } from "../../ui/primitives"; type SpacesPanelProps = { spaces: InvestigationSpace[]; @@ -36,11 +38,13 @@ export function SpacesPanel({ return (
-

Spaces

+

+ Spaces +

Save current context so you can reopen it fast.

-
+ setNameDraft(event.target.value)} @@ -53,8 +57,8 @@ export function SpacesPanel({ placeholder="Notes (optional)" aria-label="Space notes" /> - -
+ + -
+ setQuery(event.target.value)} placeholder="Search spaces" aria-label="Filter spaces" /> -
+ +
{visibleSpaces.length === 0 ? (
No spaces yet. Save the current investigation.
) : ( visibleSpaces.map((space) => ( -
{space.owner}
- - + +
- + )) )} diff --git a/codestory-ui/src/graph/GraphViewport.tsx b/codestory-ui/src/graph/GraphViewport.tsx index c756814..c93a42e 100644 --- a/codestory-ui/src/graph/GraphViewport.tsx +++ b/codestory-ui/src/graph/GraphViewport.tsx @@ -17,6 +17,7 @@ import { import { MermaidDiagram } from "../components/MermaidDiagram"; import type { EdgeKind, GraphArtifactDto } from "../generated/api"; +import { GRAPH_THEME } from "../theme/tokens"; import { buildDagreLayout } from "./layout/dagreLayout"; import { canonicalSeedFromGraphResponse } from "./layout/backendCanonical"; import { buildLegendRows, toReactFlowElements, type SemanticEdgeData } from "./layout/routing"; @@ -148,34 +149,34 @@ function isSimpleTypePillLabel(label: string): boolean { function minimapNodeColor(node: Node): string { const data = node.data; if (data?.groupMode === "file") { - return "#c6dfb4"; + return GRAPH_THEME.minimap.nodeGroupFile; } if (data?.groupMode === "namespace") { - return "#efc7cb"; + return GRAPH_THEME.minimap.nodeGroupNamespace; } if (data?.isVirtualBundle) { - return "#d4a63a"; + return GRAPH_THEME.minimap.nodeVirtualBundle; } if (data?.center) { - return "#3d434b"; + return GRAPH_THEME.minimap.nodeCenter; } if (data?.kind === "FILE") { - return "#9fc88e"; + return GRAPH_THEME.minimap.nodeFile; } if (data?.nodeStyle === "card") { - return "#c5cad2"; + return GRAPH_THEME.minimap.nodeDefault; } - return "#d8dce3"; + return GRAPH_THEME.minimap.nodeDefault; } function minimapNodeStrokeColor(node: Node): string { if (node.data?.groupMode === "file") { - return "#96bb7e"; + return GRAPH_THEME.minimap.strokeGroupFile; } if (node.data?.groupMode === "namespace") { - return "#dfb3b8"; + return GRAPH_THEME.minimap.strokeGroupNamespace; } - return node.data?.center ? "#1f252c" : "#8f98a3"; + return GRAPH_THEME.minimap.strokeDefault; } export function languageForPath(path: string | null): string { @@ -1590,8 +1591,8 @@ export function GraphViewport({ pannable zoomable position="bottom-left" - bgColor="rgb(251 251 249 / 0.92)" - maskColor="rgb(39 44 52 / 0.16)" + bgColor={GRAPH_THEME.minimap.background} + maskColor={GRAPH_THEME.minimap.mask} nodeColor={minimapNodeColor} nodeStrokeColor={minimapNodeStrokeColor} nodeBorderRadius={2} diff --git a/codestory-ui/src/graph/layout/routing.ts b/codestory-ui/src/graph/layout/routing.ts index d798356..e3de884 100644 --- a/codestory-ui/src/graph/layout/routing.ts +++ b/codestory-ui/src/graph/layout/routing.ts @@ -1,6 +1,7 @@ import { MarkerType, Position, type Edge, type Node } from "@xyflow/react"; import type { EdgeKind, GraphResponse, LayoutDirection } from "../../generated/api"; +import { EDGE_KIND_COLORS } from "../../theme/tokens"; import { PARITY_CONSTANTS } from "./parityConstants"; import type { FlowNodeData, @@ -30,19 +31,19 @@ export type SemanticEdgeData = { }; export const EDGE_STYLE: Record = { - MEMBER: { stroke: "#adb1b8", width: 2.0 }, - TYPE_USAGE: { stroke: "#7d8a99", width: 2.4 }, - USAGE: { stroke: "#1f84d6", width: 2.8 }, - CALL: { stroke: "#dfa72e", width: 2.8 }, - INHERITANCE: { stroke: "#7f7f86", width: 2.4 }, - OVERRIDE: { stroke: "#ad86c8", width: 2.4 }, - TYPE_ARGUMENT: { stroke: "#d37b93", width: 2.4 }, - TEMPLATE_SPECIALIZATION: { stroke: "#bc8fa3", width: 2.4 }, - INCLUDE: { stroke: "#87a988", width: 2.4 }, - IMPORT: { stroke: "#87a988", width: 2.4 }, - MACRO_USAGE: { stroke: "#b88b66", width: 2.4 }, - ANNOTATION_USAGE: { stroke: "#8f96b2", width: 2.4 }, - UNKNOWN: { stroke: "#8b8f96", width: 2.4 }, + MEMBER: { stroke: EDGE_KIND_COLORS.MEMBER, width: 2.0 }, + TYPE_USAGE: { stroke: EDGE_KIND_COLORS.TYPE_USAGE, width: 2.4 }, + USAGE: { stroke: EDGE_KIND_COLORS.USAGE, width: 2.8 }, + CALL: { stroke: EDGE_KIND_COLORS.CALL, width: 2.8 }, + INHERITANCE: { stroke: EDGE_KIND_COLORS.INHERITANCE, width: 2.4 }, + OVERRIDE: { stroke: EDGE_KIND_COLORS.OVERRIDE, width: 2.4 }, + TYPE_ARGUMENT: { stroke: EDGE_KIND_COLORS.TYPE_ARGUMENT, width: 2.4 }, + TEMPLATE_SPECIALIZATION: { stroke: EDGE_KIND_COLORS.TEMPLATE_SPECIALIZATION, width: 2.4 }, + INCLUDE: { stroke: EDGE_KIND_COLORS.INCLUDE, width: 2.4 }, + IMPORT: { stroke: EDGE_KIND_COLORS.IMPORT, width: 2.4 }, + MACRO_USAGE: { stroke: EDGE_KIND_COLORS.MACRO_USAGE, width: 2.4 }, + ANNOTATION_USAGE: { stroke: EDGE_KIND_COLORS.ANNOTATION_USAGE, width: 2.4 }, + UNKNOWN: { stroke: EDGE_KIND_COLORS.UNKNOWN, width: 2.4 }, }; const CLOSED_TRIANGLE_KINDS = new Set([ diff --git a/codestory-ui/src/graph/viewport/exportActions.ts b/codestory-ui/src/graph/viewport/exportActions.ts index 5de9cd6..10d3d84 100644 --- a/codestory-ui/src/graph/viewport/exportActions.ts +++ b/codestory-ui/src/graph/viewport/exportActions.ts @@ -1,6 +1,8 @@ import { useCallback, type RefObject } from "react"; import { toBlob, toJpeg, toPng, toSvg } from "html-to-image"; +import { GRAPH_THEME } from "../../theme/tokens"; + function graphExportBaseName(graphTitle: string): string { const raw = graphTitle .trim() @@ -57,7 +59,7 @@ export function useGraphExportActions({ const baseName = graphExportBaseName(graphTitle); const options = { cacheBust: true, - backgroundColor: "#f1f1ef", + backgroundColor: GRAPH_THEME.exportBackground, pixelRatio: 2, }; try { @@ -102,7 +104,7 @@ export function useGraphExportActions({ try { const blob = await toBlob(element, { cacheBust: true, - backgroundColor: "#f1f1ef", + backgroundColor: GRAPH_THEME.exportBackground, pixelRatio: 2, }); if (!blob) { diff --git a/codestory-ui/src/layout/AppShell.tsx b/codestory-ui/src/layout/AppShell.tsx index 8955d81..8c72a01 100644 --- a/codestory-ui/src/layout/AppShell.tsx +++ b/codestory-ui/src/layout/AppShell.tsx @@ -1,4 +1,7 @@ import type { ReactNode } from "react"; +import { BookMarked, Compass, Settings2 } from "lucide-react"; + +import { Button, Panel } from "../ui/primitives"; export const APP_SHELL_SECTIONS = [ { @@ -33,6 +36,11 @@ export function AppShell({ workspace, sectionContent, }: AppShellProps) { + const sectionIcons: Record = { + investigate: , + library: , + settings: , + }; const customContent = sectionContent?.[activeSection] ?? null; const activeLabel = APP_SHELL_SECTIONS.find((section) => section.id === activeSection)?.label; return ( @@ -44,16 +52,18 @@ export function AppShell({ {APP_SHELL_SECTIONS.map((section) => { const isActive = section.id === activeSection; return ( - + ); })} @@ -64,13 +74,13 @@ export function AppShell({ ) : customContent ? ( customContent ) : ( -
+

{activeLabel}

This section is not available right now. Return to Investigate to continue.

- -
+ + )}
diff --git a/codestory-ui/src/styles.css b/codestory-ui/src/styles.css index 9a8f548..d38f3b2 100644 --- a/codestory-ui/src/styles.css +++ b/codestory-ui/src/styles.css @@ -1,2888 +1,5 @@ -:root { - --font-ui: "Space Grotesk", "Segoe UI", sans-serif; - --font-mono: "JetBrains Mono", "Consolas", monospace; - --bg: oklch(0.93 0.004 95); - --bg-elevated: oklch(0.975 0.002 95); - --ink: oklch(0.28 0.01 250); - --muted: oklch(0.54 0.016 248); - --line: oklch(0.84 0.006 95); - --accent: oklch(0.79 0.14 89); - --focus: oklch(0.73 0.12 220); - --graph-canvas-top: oklch(0.975 0.002 95); - --graph-canvas-bottom: oklch(0.95 0.004 95); - --graph-chrome-bg: oklch(0.96 0.003 95 / 0.9); - --graph-chrome-border: oklch(0.85 0.005 95); - --graph-node-shell: oklch(0.92 0.002 95); - --graph-node-shell-border: oklch(0.82 0.003 95); - --graph-node-core: oklch(1 0 95); - --graph-node-core-border: oklch(0.88 0.003 95); - --graph-file-accent: oklch(0.83 0.06 135); - --graph-public-chip: oklch(0.91 0.12 86); - --graph-public-chip-border: oklch(0.82 0.08 86); - --graph-private-chip: oklch(0.92 0.06 235); - --graph-private-chip-border: oklch(0.84 0.06 235); - --surface-1: oklch(0.975 0.002 95 / 0.92); - --surface-2: oklch(0.965 0.004 96 / 0.94); - --space-2: 0.5rem; - --space-3: 0.75rem; - --space-4: 1rem; - --space-5: 1.25rem; - --duration-fast: 140ms; - --duration-medium: 220ms; -} - -* { - box-sizing: border-box; -} - -html, -body, -#root { - height: 100%; -} - -body { - margin: 0; - min-height: 100vh; - min-height: 100dvh; - font-family: var(--font-ui); - color: var(--ink); - background: - radial-gradient(circle at 10% 10%, oklch(0.9 0.018 101 / 0.75), transparent 38%), - radial-gradient(circle at 88% 24%, oklch(0.9 0.015 234 / 0.5), transparent 41%), - linear-gradient(180deg, oklch(0.94 0.004 95), oklch(0.925 0.004 94)); - overflow: auto; -} - -button, -input, -textarea { - font: inherit; -} - -.app-shell { - min-height: 100vh; - min-height: 100dvh; - min-height: 0; - display: grid; - grid-template-rows: auto auto minmax(0, 1fr); - overflow: auto; -} - -.app-body { - width: min(100%, 120rem); - margin: 0 auto; - min-height: 0; - display: grid; - grid-template-columns: minmax(220px, 260px) minmax(0, 1fr); - gap: var(--space-4); - padding: var(--space-3); - overflow: visible; -} - -.app-nav { - min-height: 0; - border: 1px solid var(--line); - border-radius: 0.95rem; - background: linear-gradient( - 160deg, - color-mix(in oklab, var(--surface-1) 90%, #fff), - color-mix(in oklab, var(--surface-2) 82%, #fff) - ); - box-shadow: 0 10px 20px rgb(17 24 31 / 0.08); - padding: var(--space-4); - display: grid; - grid-template-rows: auto auto minmax(0, 1fr); - gap: var(--space-3); -} - -.app-nav h2 { - margin: 0; - font-size: 1rem; -} - -.app-nav p { - margin: 0; - color: var(--muted); - font-size: 0.78rem; -} - -.app-nav-links { - min-height: 0; - overflow: auto; - display: grid; - gap: 0.35rem; - align-content: start; -} - -.app-nav-link { - border: 1px solid var(--line); - border-radius: 0.72rem; - background: color-mix(in oklab, #fff 92%, var(--surface-1)); - padding: 0.48rem 0.56rem; - text-align: left; - display: grid; - gap: 0.15rem; - cursor: pointer; - transition: - transform var(--duration-fast) ease, - border-color var(--duration-medium) ease, - background var(--duration-medium) ease; -} - -.app-nav-link:hover { - transform: translateY(-1px); - border-color: color-mix(in oklab, var(--focus) 34%, var(--line)); -} - -.app-nav-link span { - font-size: 0.84rem; - font-weight: 700; - color: var(--ink); -} - -.app-nav-link small { - color: var(--muted); - font-size: 0.7rem; -} - -.app-nav-link-active { - border-color: color-mix(in oklab, var(--focus) 48%, var(--line)); - background: color-mix(in oklab, #fff 74%, oklch(0.87 0.05 219)); -} - -.app-content { - min-height: 0; - overflow: auto; - display: flex; -} - -.app-placeholder-card { - width: 100%; - border: 1px solid var(--line); - border-radius: 1rem; - background: color-mix(in oklab, #fff 88%, var(--surface-1)); - display: grid; - place-content: center; - gap: 0.6rem; - text-align: center; - padding: 1.25rem; - box-shadow: 0 10px 20px rgb(17 24 31 / 0.08); -} - -.app-placeholder-card h3 { - margin: 0; -} - -.app-placeholder-card p { - margin: 0; - color: var(--muted); - max-width: 34rem; -} - -.app-placeholder-card button { - justify-self: center; - border: 1px solid var(--line); - border-radius: 0.65rem; - background: #fff; - padding: 0.38rem 0.72rem; - cursor: pointer; -} - -.topbar { - display: flex; - justify-content: space-between; - align-items: center; - gap: 1rem; - padding: 0.9rem var(--space-5); - border-bottom: 1px solid var(--line); - background: color-mix(in oklab, var(--bg-elevated) 96%, #fff); - backdrop-filter: blur(8px); -} - -.brand h1 { - margin: 0; - line-height: 1; - font-size: 1.3rem; -} - -.brand p { - margin: 0.24rem 0 0; - color: var(--muted); - font-size: 0.86rem; -} - -.topbar-actions { - display: flex; - gap: 0.5rem; - align-items: center; - flex-wrap: wrap; -} - -.topbar-actions button { - border: 1px solid color-mix(in oklab, var(--line) 70%, #0000); - border-radius: 0.62rem; - background: #fff; - padding: 0.48rem 0.74rem; - font-weight: 600; - cursor: pointer; - transition: - border-color 180ms ease, - transform 180ms ease; -} - -.topbar-actions button:hover { - transform: translateY(-1px); - border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); -} - -.topbar-actions button:disabled { - opacity: 0.58; - cursor: not-allowed; - transform: none; -} - -.path-input { - min-width: 16rem; - border: 1px solid var(--line); - border-radius: 0.65rem; - padding: 0.48rem 0.62rem; - background: #fff; -} - -.status-strip { - display: flex; - justify-content: space-between; - gap: 0.7rem; - padding: 0.5rem var(--space-5); - border-bottom: 1px solid var(--line); - color: var(--muted); - font-size: 0.88rem; - background: color-mix(in oklab, #fff 88%, oklch(0.86 0.045 92)); -} - -.workspace { - display: grid; - grid-template-columns: minmax(300px, 1fr) minmax(420px, 1.25fr) minmax(360px, 1.05fr); - gap: 0.74rem; - padding: 0; - min-height: 0; - overflow: hidden; - width: 100%; -} - -.investigate-layout { - width: 100%; - min-height: 0; - display: grid; - grid-template-rows: auto auto minmax(0, 1fr); - gap: var(--space-3); -} - -.investigate-toolbar { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--space-3); - flex-wrap: wrap; - border: 1px solid var(--line); - border-radius: 0.85rem; - background: color-mix(in oklab, #fff 92%, var(--surface-1)); - padding: 0.5rem 0.6rem; -} - -.investigate-toolbar-actions { - display: inline-flex; - align-items: center; - gap: 0.4rem; -} - -.investigate-toolbar-actions button { - border: 1px solid var(--line); - border-radius: 0.55rem; - background: #fff; - padding: 0.35rem 0.6rem; - cursor: pointer; -} - -.investigate-pane { - min-height: min(68vh, 56rem); - max-height: min(74vh, 60rem); - overflow: hidden; - display: flex; -} - -.investigate-pane > .pane { - width: 100%; -} - -.focus-switcher { - display: inline-flex; - align-items: center; - border: 1px solid var(--line); - border-radius: 999px; - background: #fff; - padding: 0.16rem; - gap: 0.2rem; -} - -.focus-switcher-item { - border: none; - border-radius: 999px; - background: transparent; - color: var(--muted); - padding: 0.34rem 0.72rem; - font-size: 0.8rem; - font-weight: 600; - cursor: pointer; -} - -.focus-switcher-item-active { - color: var(--ink); - background: color-mix(in oklab, #fff 78%, oklch(0.86 0.05 219)); -} - -.starter-card { - border: 1px solid var(--line); - border-radius: 0.9rem; - background: color-mix(in oklab, #fff 92%, var(--surface-1)); - box-shadow: 0 8px 18px rgb(17 24 31 / 0.06); - padding: 0.75rem; - display: grid; - gap: 0.5rem; -} - -.starter-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.5rem; -} - -.starter-header h2 { - margin: 0; - font-size: 0.95rem; -} - -.starter-dismiss { - border: none; - background: transparent; - color: var(--muted); - cursor: pointer; -} - -.starter-status-chips { - display: flex; - flex-wrap: wrap; - gap: 0.4rem; -} - -.starter-chip { - border: 1px solid var(--line); - border-radius: 999px; - padding: 0.2rem 0.56rem; - font-size: 0.72rem; - color: var(--muted); - background: #fff; -} - -.starter-chip-ready { - color: color-mix(in oklab, var(--ink) 85%, #124e2a); - border-color: color-mix(in oklab, var(--line) 55%, oklch(0.74 0.08 145)); - background: color-mix(in oklab, #fff 84%, oklch(0.92 0.05 145)); -} - -.starter-next-step { - display: grid; - gap: 0.22rem; -} - -.starter-next-step p { - margin: 0; - color: var(--muted); - font-size: 0.8rem; -} - -.starter-primary { - justify-self: start; - border: 1px solid color-mix(in oklab, var(--line) 45%, var(--focus)); - border-radius: 0.56rem; - background: color-mix(in oklab, #fff 75%, oklch(0.87 0.05 219)); - color: var(--ink); - padding: 0.35rem 0.72rem; - cursor: pointer; - font-weight: 600; -} - -.starter-help-toggle { - justify-self: start; - border: none; - background: transparent; - color: var(--muted); - cursor: pointer; - padding: 0; -} - -.starter-help { - border: 1px dashed var(--line); - border-radius: 0.66rem; - background: #fff; - padding: 0.48rem 0.56rem; -} - -.starter-help p { - margin: 0; - color: var(--muted); - font-size: 0.78rem; -} - -.pane { - min-height: 0; - max-height: 100%; - border: 1px solid var(--line); - border-radius: 0.95rem; - background: color-mix(in oklab, var(--bg-elevated) 95%, #fff); - box-shadow: 0 10px 22px rgba(18, 24, 28, 0.08); - display: flex; - flex-direction: column; - overflow: hidden; -} - -.pane-header { - padding: 0.65rem 0.75rem; - border-bottom: 1px solid var(--line); - display: flex; - justify-content: space-between; - gap: 0.5rem; - align-items: center; -} - -.pane-header h2 { - margin: 0; - font-size: 0.92rem; - letter-spacing: 0.01em; -} - -.tabs, -.graph-tabs { - display: flex; - gap: 0.35rem; - flex-wrap: wrap; -} - -.tabs button, -.graph-tabs button { - border: 1px solid var(--line); - border-radius: 999px; - padding: 0.3rem 0.55rem; - background: #fff; - font-size: 0.76rem; - cursor: pointer; -} - -.tab-active { - background: var(--accent) !important; - border-color: color-mix(in oklab, var(--accent) 60%, #393939) !important; -} - -.pane-response { - overflow: auto; -} - -.prompt-box, -.card { - margin: 0.7rem; - border: 1px solid var(--line); - border-radius: 0.86rem; - background: #fff; -} - -.prompt-box textarea { - width: 100%; - min-height: 6.8rem; - resize: vertical; - border: none; - outline: none; - border-radius: 0.86rem 0.86rem 0 0; - padding: 0.75rem; - background: #fff; -} - -.agent-connection-settings { - display: grid; - grid-template-columns: minmax(7rem, 11rem) minmax(0, 1fr); - gap: 0.5rem; - padding: 0.52rem 0.7rem; - border-top: 1px solid var(--line); - background: color-mix(in oklab, #fff 88%, oklch(0.91 0.03 95)); -} - -.agent-connection-field { - min-width: 0; - display: grid; - gap: 0.2rem; -} - -.agent-connection-field span { - font-family: var(--font-mono); - font-size: 0.66rem; - color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.02em; -} - -.agent-connection-field select, -.agent-connection-field input { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.5rem; - background: #fff; - min-height: 1.85rem; - padding: 0.24rem 0.46rem; -} - -.retrieval-profile-settings { - display: grid; - gap: 0.5rem; - padding: 0.52rem 0.7rem; - border-top: 1px solid var(--line); - background: color-mix(in oklab, #fff 90%, oklch(0.9 0.04 95)); -} - -.custom-profile-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); - gap: 0.48rem; -} - -.agent-connection-field-wide { - grid-column: 1 / -1; -} - -.profile-checkbox { - display: inline-flex; - align-items: center; - gap: 0.35rem; - color: var(--muted); - font-size: 0.75rem; -} - -.prompt-actions { - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.65rem; - border-top: 1px solid var(--line); - padding: 0.54rem 0.72rem; - background: color-mix(in oklab, #fff 85%, oklch(0.89 0.05 95)); -} - -.prompt-actions-meta { - color: var(--muted); - font-size: 0.74rem; -} - -.prompt-actions button, -.graph-links button, -.tree-label { - border: 1px solid var(--line); - border-radius: 0.64rem; - background: #fff; - padding: 0.33rem 0.62rem; - cursor: pointer; -} - -.card { - padding: 0.62rem; -} - -.card h3, -.card h4 { - margin: 0 0 0.52rem; -} - -.section-block { - border-top: 1px solid var(--line); - padding-top: 0.58rem; - margin-top: 0.58rem; -} - -.section-block-content { - display: grid; - gap: 0.5rem; -} - -.response-block { - min-width: 0; -} - -.section-markdown { - margin: 0; - white-space: pre-wrap; - font-family: var(--font-mono); - font-size: 0.76rem; - color: color-mix(in oklab, var(--ink) 90%, #000 9%); - background: color-mix(in oklab, #fff 82%, oklch(0.88 0.045 95)); - border: 1px solid var(--line); - border-radius: 0.68rem; - padding: 0.58rem; -} - -.inline-mermaid-block { - border: 1px solid var(--line); - border-radius: 0.68rem; - background: color-mix(in oklab, #fff 88%, #e8eaeb); - overflow: hidden; -} - -.inline-mermaid { - max-height: 22rem; - padding: 0.75rem; -} - -.graph-links { - display: flex; - gap: 0.35rem; - flex-wrap: wrap; - margin-top: 0.52rem; -} - -.trace-panel { - margin-top: 0.65rem; - border: 1px solid var(--line); - border-radius: 0.68rem; - padding: 0.52rem; - background: color-mix(in oklab, #fff 90%, oklch(0.9 0.04 95)); -} - -.trace-panel summary { - cursor: pointer; - font-family: var(--font-mono); - font-size: 0.72rem; - color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.02em; -} - -.trace-panel pre { - margin: 0.5rem 0 0; - white-space: pre-wrap; - font-family: var(--font-mono); - font-size: 0.7rem; - color: color-mix(in oklab, var(--ink) 90%, #000 9%); -} - -.explorer-card { - min-height: 16rem; - display: flex; - flex-direction: column; - gap: 0.55rem; -} - -.explorer-card p { - margin: 0; - color: var(--muted); -} - -.explorer-toolbar { - border: 1px solid var(--line); - border-radius: 0.68rem; - padding: 0.48rem 0.52rem; - display: grid; - gap: 0.44rem; - background: color-mix(in oklab, #fff 86%, oklch(0.91 0.035 95)); -} - -.explorer-search-input { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.58rem; - padding: 0.36rem 0.52rem; - background: #fff; -} - -.explorer-search-input:focus { - outline: 2px solid color-mix(in oklab, var(--focus) 48%, transparent); - outline-offset: 1px; -} - -.explorer-toolbar-row { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 0.55rem; - color: var(--muted); - font-size: 0.76rem; -} - -.explorer-toolbar-row label { - display: inline-flex; - align-items: center; - gap: 0.28rem; -} - -.explorer-clear-button { - margin-left: auto; - border: 1px solid var(--line); - border-radius: 0.52rem; - background: #fff; - padding: 0.22rem 0.5rem; - cursor: pointer; -} - -.explorer-clear-button:disabled { - opacity: 0.58; - cursor: default; -} - -.explorer-summary { - display: flex; - flex-wrap: wrap; - gap: 0.34rem; - color: var(--muted); - font-size: 0.72rem; -} - -.explorer-summary span { - border: 1px solid color-mix(in oklab, var(--line) 80%, #0000); - border-radius: 999px; - padding: 0.12rem 0.42rem; - background: #fff; -} - -.tree-root { - min-height: 0; - overflow: auto; - border: 1px solid var(--line); - border-radius: 0.7rem; - padding: 0.28rem; - background: color-mix(in oklab, #fff 92%, oklch(0.92 0.03 95)); - scrollbar-width: thin; - display: flex; - flex-direction: column; - gap: 0.14rem; -} - -.tree-node { - display: flex; - gap: 0.24rem; - align-items: stretch; -} - -.tree-node-active .tree-label { - border-color: color-mix(in oklab, var(--focus) 35%, var(--line)); - background: color-mix(in oklab, #fff 80%, oklch(0.88 0.04 219)); -} - -.tree-toggle { - width: 1.42rem; - min-height: 2.15rem; - border-radius: 0.4rem; - border: 1px solid var(--line); - background: #fff; - cursor: pointer; -} - -.tree-toggle-empty { - opacity: 0.55; -} - -.tree-label { - flex: 1; - text-align: left; - display: flex; - flex-direction: column; - align-items: stretch; - gap: 0.15rem; - overflow: hidden; -} - -.tree-label-top { - min-width: 0; - display: inline-flex; - align-items: center; - gap: 0.4rem; -} - -.tree-name { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-weight: 600; -} - -.tree-path { - font-family: var(--font-mono); - font-size: 0.67rem; - color: var(--muted); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.kind-pill { - flex: none; - font-size: 0.62rem; - border-radius: 999px; - border: 1px solid color-mix(in oklab, var(--accent) 65%, var(--line)); - background: color-mix(in oklab, var(--accent) 44%, #fff); - padding: 0.1rem 0.4rem; -} - -.tree-duplicate-pill { - flex: none; - font-family: var(--font-mono); - font-size: 0.64rem; - border-radius: 999px; - border: 1px solid color-mix(in oklab, var(--line) 90%, #697177); - background: color-mix(in oklab, #fff 92%, oklch(0.88 0.02 250)); - color: color-mix(in oklab, var(--muted) 76%, var(--ink)); - padding: 0.06rem 0.34rem; -} - -.explorer-empty { - margin: 0.34rem; - border: 1px dashed var(--line); - border-radius: 0.56rem; - padding: 0.72rem; - color: var(--muted); - font-size: 0.8rem; - text-align: center; - background: #fff; -} - -.pane-graph { - min-height: 0; -} - -.graph-header { - display: grid; - grid-template-columns: auto minmax(200px, 360px) minmax(0, 1fr); - align-items: center; - gap: 0.6rem; -} - -.graph-header-title { - display: inline-flex; - align-items: center; - gap: 0.4rem; -} - -.graph-trail-controls { - border-bottom: 1px solid var(--line); - padding: 0.46rem 0.62rem 0.5rem; - display: grid; - gap: 0.38rem; - background: color-mix(in oklab, #fff 90%, oklch(0.9 0.02 95)); -} - -.graph-trail-toolbar { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 0.32rem; -} - -.graph-trail-toolbar button { - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.22rem 0.52rem; - font-size: 0.72rem; - cursor: pointer; -} - -.graph-trail-toolbar button:disabled { - opacity: 0.58; - cursor: default; -} - -.graph-control-field { - min-width: 0; - display: grid; - gap: 0.22rem; - font-size: 0.72rem; - color: var(--muted); -} - -.graph-control-field span { - font-family: var(--font-mono); - text-transform: uppercase; - letter-spacing: 0.02em; -} - -.graph-control-field select, -.graph-control-field input { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.5rem; - background: #fff; - min-height: 1.9rem; - padding: 0.26rem 0.44rem; -} - -.trail-dialog-backdrop { - position: fixed; - inset: 0; - background: rgb(17 19 22 / 0.42); - display: grid; - place-items: center; - z-index: 60; -} - -.trail-dialog { - width: min(58rem, calc(100vw - 1.6rem)); - max-height: calc(100vh - 2rem); - border: 1px solid var(--line); - border-radius: 0.86rem; - background: #fff; - box-shadow: 0 22px 42px rgb(12 18 24 / 0.24); - padding: 0.9rem; - overflow: auto; - display: grid; - gap: 0.62rem; -} - -.trail-dialog-header { - display: flex; - align-items: center; - justify-content: space-between; -} - -.trail-dialog-header h3 { - margin: 0; -} - -.trail-dialog-grid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 0.52rem; -} - -.trail-dialog-grid-secondary { - grid-template-columns: repeat(3, minmax(0, 1fr)); -} - -.trail-target-field { - position: relative; -} - -.trail-target-placeholder { - display: grid; - gap: 0.22rem; - font-size: 0.72rem; - color: var(--muted); -} - -.trail-target-placeholder span { - font-family: var(--font-mono); - text-transform: uppercase; - letter-spacing: 0.02em; -} - -.trail-target-placeholder-value { - min-height: 1.9rem; - border: 1px solid var(--line); - border-radius: 0.5rem; - background: color-mix(in oklab, #fff 92%, #f3f4f6); - display: flex; - align-items: center; - padding: 0.26rem 0.44rem; -} - -.trail-mode-row { - display: flex; - flex-wrap: wrap; - gap: 0.64rem; - border: 1px solid var(--line); - border-radius: 0.66rem; - padding: 0.5rem; - background: color-mix(in oklab, #fff 92%, oklch(0.9 0.02 95)); -} - -.trail-mode-option { - display: inline-flex; - align-items: center; - gap: 0.32rem; - font-size: 0.78rem; -} - -.trail-range-value { - font-size: 0.7rem; - color: var(--muted); - font-family: var(--font-mono); -} - -.trail-inline-options { - display: flex; - flex-wrap: wrap; - gap: 0.64rem; -} - -.trail-filter-columns { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 0.62rem; -} - -.trail-filter-column { - border: 1px solid var(--line); - border-radius: 0.66rem; - background: color-mix(in oklab, #fff 95%, oklch(0.9 0.02 95)); - padding: 0.48rem; - display: grid; - gap: 0.42rem; -} - -.trail-filter-header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.4rem; -} - -.trail-filter-actions { - display: inline-flex; - gap: 0.25rem; -} - -.trail-filter-actions button { - border: 1px solid var(--line); - border-radius: 999px; - background: #fff; - font-size: 0.64rem; - padding: 0.08rem 0.44rem; - cursor: pointer; -} - -.trail-filter-list { - max-height: 12rem; - overflow: auto; - display: grid; - gap: 0.24rem; - padding-right: 0.22rem; -} - -.trail-filter-item { - display: inline-flex; - align-items: center; - gap: 0.34rem; - font-size: 0.74rem; -} - -.trail-dialog-actions { - display: flex; - justify-content: flex-end; - gap: 0.4rem; -} - -.trail-dialog-actions button { - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.26rem 0.62rem; - cursor: pointer; -} - -.trail-dialog-actions button:disabled { - opacity: 0.58; - cursor: default; -} - -.graph-target-clear { - width: fit-content; - border: 1px solid var(--line); - border-radius: 999px; - background: #fff; - font-size: 0.68rem; - padding: 0.14rem 0.48rem; - cursor: pointer; -} - -.graph-filter-row { - display: grid; - gap: 0.28rem; -} - -.graph-filter-label { - font-family: var(--font-mono); - font-size: 0.68rem; - letter-spacing: 0.02em; - color: var(--muted); - text-transform: uppercase; -} - -.graph-chip-row { - display: flex; - flex-wrap: wrap; - gap: 0.24rem; -} - -.graph-chip-row-grouping { - margin-top: 0.18rem; -} - -.graph-chip { - border: 1px solid var(--line); - border-radius: 999px; - background: #fff; - font-size: 0.67rem; - padding: 0.14rem 0.44rem; - cursor: pointer; -} - -.graph-chip-active { - border-color: color-mix(in oklab, var(--focus) 50%, var(--line)); - background: color-mix(in oklab, #fff 80%, oklch(0.88 0.05 219)); - color: color-mix(in oklab, var(--ink) 85%, #0a2238); -} - -.graph-filter-details { - border: 1px solid color-mix(in oklab, var(--line) 84%, #f0f0f0); - border-radius: 0.5rem; - background: color-mix(in oklab, #fff 92%, oklch(0.92 0.03 95)); - padding: 0.28rem 0.36rem 0.38rem; -} - -.graph-filter-details summary { - cursor: pointer; - font-size: 0.7rem; - color: var(--muted); - margin-bottom: 0.3rem; -} - -.graph-chip-row-node { - margin-top: 0.2rem; -} - -.graph-trail-actions { - display: flex; - align-items: center; - gap: 0.38rem; - flex-wrap: wrap; -} - -.graph-trail-actions button { - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.3rem 0.56rem; - cursor: pointer; -} - -.graph-trail-actions button:disabled { - opacity: 0.58; - cursor: default; -} - -.graph-trail-reason, -.graph-trail-hint { - font-size: 0.72rem; - color: var(--muted); -} - -.graph-trail-reason { - padding-left: 0.1rem; -} - -.graph-trail-hint { - padding-left: 0.1rem; -} - -.trail-target-state { - position: absolute; - right: 0.52rem; - top: 1.9rem; - transform: translateY(-50%); - font-size: 0.66rem; - color: var(--muted); - pointer-events: none; -} - -.truncation-pill { - border: 1px solid color-mix(in oklab, var(--accent) 65%, #5e5d43); - background: color-mix(in oklab, var(--accent) 38%, #fff); - border-radius: 999px; - padding: 0.14rem 0.46rem; - font-size: 0.68rem; - font-weight: 700; -} - -.graph-search-wrap { - position: relative; - min-width: 0; -} - -.graph-search-input { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.62rem; - padding: 0.42rem 0.58rem; - background: #fff; -} - -.graph-search-input:focus { - outline: 2px solid color-mix(in oklab, var(--focus) 50%, transparent); - outline-offset: 1px; -} - -.search-state { - position: absolute; - right: 0.52rem; - top: 50%; - transform: translateY(-50%); - font-size: 0.67rem; - color: var(--muted); - pointer-events: none; -} - -.search-dropdown { - position: absolute; - z-index: 30; - top: calc(100% + 0.3rem); - left: 0; - right: 0; - background: #fff; - border: 1px solid var(--line); - border-radius: 0.7rem; - box-shadow: 0 12px 24px rgba(15, 23, 27, 0.16); - max-height: 16rem; - overflow-y: auto; - overflow-x: hidden; - padding: 0.3rem; -} - -.search-hit { - width: 100%; - border: 1px solid transparent; - border-radius: 0.58rem; - background: #fff; - text-align: left; - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.5rem; - padding: 0.34rem 0.5rem; - cursor: pointer; - font-size: 0.78rem; - min-width: 0; -} - -.search-hit-name { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.search-hit-kind { - flex: none; - font-family: var(--font-mono); - font-size: 0.68rem; - color: var(--muted); - letter-spacing: 0.02em; - text-transform: uppercase; -} - -.graph-tabs { - min-width: 0; - flex-wrap: nowrap; - overflow-x: auto; - overflow-y: hidden; - scrollbar-width: thin; - padding-bottom: 0.16rem; -} - -.graph-tabs button { - flex: 0 0 auto; - max-width: 18rem; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.search-hit:hover, -.search-hit-active { - border-color: color-mix(in oklab, var(--focus) 30%, var(--line)); - background: color-mix(in oklab, #fff 80%, oklch(0.88 0.05 95)); -} - -.graph-canvas { - min-height: 0; - flex: 1; - background: - radial-gradient(circle at 7% 12%, rgb(255 255 255 / 0.7), transparent 30%), - radial-gradient(circle at 86% 16%, rgb(255 255 255 / 0.38), transparent 34%), - linear-gradient(180deg, var(--graph-canvas-top), var(--graph-canvas-bottom)); -} - -.graph-flow-shell { - position: relative; - width: 100%; - height: 100%; -} - -.graph-context-menu { - position: absolute; - z-index: 45; - min-width: 12rem; - border: 1px solid var(--graph-chrome-border); - border-radius: 0.66rem; - background: color-mix(in oklab, #fff 90%, var(--graph-chrome-bg)); - box-shadow: 0 14px 24px rgb(14 20 26 / 0.2); - padding: 0.3rem; - display: grid; - gap: 0.2rem; -} - -.graph-context-menu button { - width: 100%; - border: 1px solid transparent; - border-radius: 0.5rem; - background: transparent; - text-align: left; - font-size: 0.74rem; - padding: 0.24rem 0.42rem; - cursor: pointer; - color: var(--ink); -} - -.graph-context-menu button:hover { - border-color: color-mix(in oklab, var(--graph-chrome-border) 72%, #fff); - background: color-mix(in oklab, #fff 68%, var(--graph-chrome-bg)); -} - -.sourcetrail-flow .react-flow__renderer { - background: transparent; -} - -.sourcetrail-flow .react-flow__pane { - cursor: grab; -} - -.sourcetrail-flow .react-flow__pane:active { - cursor: grabbing; -} - -.sourcetrail-flow .react-flow__edge-path { - stroke-linecap: round; - stroke-linejoin: round; -} - -.sourcetrail-flow .react-flow__controls { - border: 1px solid var(--graph-chrome-border); - border-radius: 0.72rem; - box-shadow: 0 8px 18px rgb(15 19 23 / 0.14); - background: var(--graph-chrome-bg); - gap: 0.14rem; - padding: 0.1rem; -} - -.sourcetrail-flow .react-flow__controls button { - border: 1px solid var(--graph-chrome-border); - border-radius: 0.52rem; - background: color-mix(in oklab, #fff 84%, var(--graph-chrome-bg)); - color: #5f6670; - box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.45); -} - -.sourcetrail-flow .react-flow__controls button:hover { - background: color-mix(in oklab, #fff 72%, var(--graph-chrome-bg)); -} - -.sourcetrail-flow .react-flow__minimap, -.graph-minimap { - border: 1px solid var(--graph-chrome-border); - border-radius: 0.72rem; - box-shadow: 0 8px 18px rgb(15 19 23 / 0.14); - background: color-mix(in oklab, #fff 88%, var(--graph-chrome-bg)); -} - -.sourcetrail-flow .react-flow__minimap-mask { - fill: rgb(39 44 52 / 0.16); -} - -.sourcetrail-flow .react-flow__minimap-node { - stroke-width: 0.95; -} - -.graph-zoom-panel { - display: grid; - gap: 0.2rem; - margin-bottom: 0.4rem; -} - -.graph-zoom-panel button, -.graph-legend-toggle-panel button { - min-width: 1.9rem; - min-height: 1.9rem; - border: 1px solid var(--graph-chrome-border); - border-radius: 0.56rem; - background: color-mix(in oklab, #fff 84%, var(--graph-chrome-bg)); - color: #4d545d; - font-family: var(--font-mono); - font-size: 0.78rem; - font-weight: 700; - box-shadow: - inset 0 1px 0 rgb(255 255 255 / 0.45), - 0 6px 14px rgb(15 19 23 / 0.12); - cursor: pointer; -} - -.graph-zoom-panel button:hover, -.graph-legend-toggle-panel button:hover { - background: color-mix(in oklab, #fff 72%, var(--graph-chrome-bg)); -} - -.graph-legend-toggle-panel { - margin-bottom: 0.2rem; -} - -.graph-legend-panel { - min-width: 10rem; - border: 1px solid var(--graph-chrome-border); - border-radius: 0.74rem; - background: color-mix(in oklab, #fff 84%, var(--graph-chrome-bg)); - box-shadow: 0 10px 22px rgb(14 20 26 / 0.16); - padding: 0.45rem 0.5rem; - margin-bottom: 2.4rem; -} - -.graph-legend-title { - font-family: var(--font-mono); - font-size: 0.68rem; - text-transform: uppercase; - letter-spacing: 0.02em; - color: var(--muted); - margin-bottom: 0.3rem; -} - -.graph-legend-rows { - display: grid; - gap: 0.18rem; -} - -.graph-legend-row { - width: 100%; - border: 1px solid transparent; - border-radius: 0.5rem; - background: transparent; - padding: 0.18rem 0.2rem; - display: grid; - grid-template-columns: 1.2rem 1fr auto; - align-items: center; - gap: 0.3rem; - text-align: left; - cursor: pointer; -} - -.graph-legend-row:hover { - border-color: color-mix(in oklab, var(--graph-chrome-border) 72%, #fff); - background: color-mix(in oklab, #fff 62%, var(--graph-chrome-bg)); -} - -.graph-legend-row-muted { - opacity: 0.45; -} - -.graph-legend-row-active { - opacity: 1; -} - -.graph-legend-line { - display: inline-block; - height: 0.2rem; - border-radius: 999px; -} - -.graph-legend-kind { - font-size: 0.7rem; - color: var(--ink); -} - -.graph-legend-count { - font-family: var(--font-mono); - font-size: 0.66rem; - color: var(--muted); -} - -.graph-legend-note { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 0.35rem; - margin-top: 0.42rem; - font-size: 0.64rem; - color: var(--muted); - line-height: 1.35; -} - -.graph-legend-reset { - border: 1px solid var(--graph-chrome-border); - border-radius: 999px; - background: #fff; - color: #4f5660; - font-family: var(--font-mono); - font-size: 0.62rem; - padding: 0.08rem 0.44rem; - cursor: pointer; -} - -.graph-node { - position: relative; - min-width: 210px; - border-radius: 18px; - border: 1px solid var(--graph-node-shell-border); - background: var(--graph-node-shell); - padding: 0.58rem 0.6rem 0.64rem; - box-shadow: 0 4px 12px rgb(0 0 0 / 0.05); - color: #1c1f23; - transition: box-shadow 180ms ease; -} - -.graph-node-file { - border-color: color-mix(in oklab, var(--graph-file-accent) 52%, var(--graph-node-shell-border)); - box-shadow: - inset 0 1px 0 rgb(255 255 255 / 0.45), - 0 0 0 2px color-mix(in oklab, var(--graph-file-accent) 35%, transparent); -} - -.graph-node-file-tab { - position: absolute; - left: -0.5rem; - top: -1.66rem; - border: 1px solid - color-mix(in oklab, var(--graph-file-accent) 56%, var(--graph-node-shell-border)); - border-bottom: none; - border-radius: 0.8rem 0.8rem 0 0; - background: color-mix(in oklab, var(--graph-file-accent) 76%, #fff); - padding: 0.22rem 0.88rem 0.26rem; - font-family: var(--font-mono); - font-size: 0.76rem; - letter-spacing: 0.01em; - font-weight: 700; - color: color-mix(in oklab, #354046 72%, #000); -} - -.graph-node-title-row { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.5rem; - margin-bottom: 0.42rem; -} - -.graph-node-title { - font-family: var(--font-mono); - font-size: 0.86rem; - letter-spacing: 0.01em; -} - -.graph-node-count { - min-width: 1.9rem; - border-radius: 999px; - border: 1px solid color-mix(in oklab, var(--graph-node-core-border) 70%, #9da3ab); - background: color-mix(in oklab, var(--graph-node-core) 74%, #ebedf0); - padding: 0.12rem 0.46rem; - text-align: center; - font-family: var(--font-mono); - font-size: 0.7rem; - font-weight: 700; - color: #1d2125; -} - -.graph-node-toggle { - display: inline-flex; - align-items: center; - gap: 0.28rem; - border: none; - background: transparent; - padding: 0; - cursor: pointer; -} - -.graph-node-toggle:disabled { - cursor: default; -} - -.graph-node-chevron { - font-family: var(--font-mono); - font-size: 0.68rem; - color: #4d545c; - line-height: 1; -} - -.graph-node-body { - border-radius: 14px; - border: 1px solid var(--graph-node-core-border); - background: var(--graph-node-core); - min-height: 2.7rem; - padding: 0.52rem; - display: flex; - flex-direction: column; - gap: 0.4rem; -} - -.graph-node-section { - width: 100%; - border-radius: 0.68rem; - border: 1px solid color-mix(in oklab, var(--graph-node-core-border) 88%, #efefef); - background: color-mix(in oklab, #fff 94%, var(--graph-node-core)); - padding: 0.38rem 0.38rem 0.35rem; -} - -.graph-node-section-empty { - border-style: dashed; -} - -.graph-node-section-header { - width: 100%; - display: flex; - align-items: center; - gap: 0.34rem; - margin-bottom: 0.36rem; - padding-bottom: 0.2rem; - border-bottom: 1px dashed color-mix(in oklab, var(--graph-node-core-border) 74%, #d8dadd); - letter-spacing: 0.01em; - font-family: var(--font-mono); - font-size: 0.71rem; - font-weight: 700; - color: #2f353b; - text-transform: uppercase; -} - -.graph-node-section-title { - line-height: 1; -} - -.graph-node-section-count { - margin-left: auto; - border-radius: 999px; - border: 1px solid color-mix(in oklab, var(--graph-node-core-border) 84%, #969ca4); - background: color-mix(in oklab, #fff 78%, var(--graph-node-core)); - padding: 0.04rem 0.34rem; - font-size: 0.62rem; - color: #596069; - line-height: 1.2; -} - -.graph-node-section-count-public { - border-color: color-mix(in oklab, var(--graph-public-chip-border) 82%, #8c8d7e); - background: color-mix(in oklab, var(--graph-public-chip) 24%, #fff); -} - -.graph-node-section-count-private { - border-color: color-mix(in oklab, var(--graph-private-chip-border) 82%, #7e8796); - background: color-mix(in oklab, var(--graph-private-chip) 24%, #fff); -} - -.graph-section-dot { - display: flex; - align-items: center; - justify-content: center; - font-size: 0.8rem; - line-height: 1; - color: #6a727a; -} - -.graph-node-members { - width: 100%; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 0.34rem; -} - -.graph-member-chip { - position: relative; - display: flex; - align-items: center; - min-height: 1.44rem; - border-radius: 999px; - border: 1px solid var(--graph-public-chip-border); - background: var(--graph-public-chip); - padding: 0.18rem 0.58rem; - max-width: 100%; - transition: - border-color 160ms ease, - box-shadow 160ms ease, - background 160ms ease; -} - -.graph-member-chip-button { - width: 100%; - appearance: none; - text-align: left; - cursor: pointer; -} - -.graph-member-chip-public { - border-color: #f7dca1; - background: #fdf2d0; -} - -.graph-member-chip-private { - border-color: #b3d1e6; - background: #e6f3fc; -} - -.graph-member-chip-focused { - border-color: color-mix(in oklab, var(--focus) 60%, #516270); - background: color-mix(in oklab, #fff 66%, var(--focus)); - box-shadow: - 0 0 0 1px color-mix(in oklab, var(--focus) 46%, transparent), - inset 0 1px 0 rgb(255 255 255 / 0.54); -} - -.graph-node-center .graph-member-chip-focused { - border-color: color-mix(in oklab, var(--focus) 72%, #2f3a48); - box-shadow: - 0 0 0 2px color-mix(in oklab, var(--focus) 38%, transparent), - inset 0 1px 0 rgb(255 255 255 / 0.64); -} - -.graph-node-center .graph-member-chip-focused .graph-member-name { - font-weight: 700; -} - -.graph-member-name { - font-family: var(--font-mono); - font-size: 0.72rem; - color: #15181c; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.graph-member-more { - font-family: var(--font-mono); - font-size: 0.66rem; - color: #6a727a; - padding-left: 0.22rem; -} - -.graph-node-center { - border: 2px solid #555; -} - -.graph-node-selected { - box-shadow: - 0 0 0 2px rgb(47 58 65 / 0.28), - inset 0 1px 0 rgb(255 255 255 / 0.42); -} - -.graph-floating-pill { - position: relative; - display: inline-flex; - align-items: center; - gap: 0.3rem; - min-width: 3.7rem; - width: fit-content; - max-width: none; - border-radius: 999px; - border: 1px solid #c2c9d1; - background: #ebedf0; - padding: 0.34rem 0.76rem; - font-family: var(--font-mono); - font-size: 0.74rem; - color: #101215; - line-height: 1.1; - white-space: nowrap; -} - -.graph-pill-duplicate-count { - margin-left: 0.38rem; - border-radius: 999px; - border: 1px solid color-mix(in oklab, var(--graph-public-chip-border) 70%, #9f8b57); - background: color-mix(in oklab, var(--graph-public-chip) 62%, #fff); - padding: 0.08rem 0.34rem; - font-size: 0.64rem; - font-weight: 700; -} - -.graph-floating-pill-center { - border-color: #31353c; - box-shadow: 0 0 0 2px rgba(49, 53, 60, 0.45); -} - -.graph-floating-pill-selected { - box-shadow: 0 0 0 2px rgba(49, 53, 60, 0.35); -} - -.graph-floating-pill-simple { - border-style: solid; - border-color: #d1d6dc; - background: repeating-linear-gradient(-45deg, #f5f7f9 0 8px, #e2e6eb 8px 16px); - color: #2f353b; - box-shadow: none; -} - -.graph-node-unresolved { - background-image: repeating-linear-gradient( - -45deg, - rgb(227 232 238 / 0.82) 0 9px, - rgb(245 247 250 / 0.95) 9px 18px - ); -} - -.graph-bundle-node { - width: 6px; - height: 6px; - border-radius: 999px; - background: transparent; - border: none; - box-shadow: none; - opacity: 0; - pointer-events: none; -} - -.react-flow__node-sourcetrailGroup { - background: transparent !important; - border: none !important; - box-shadow: none !important; - padding: 0 !important; -} - -.graph-group-node { - width: 100%; - height: 100%; - border: 2px solid #d7dade; - border-radius: 1rem; - background: color-mix(in oklab, #fff 64%, var(--graph-node-shell)); - pointer-events: none; - position: relative; -} - -.graph-group-node-file { - border-color: #aacd95; - background: color-mix(in oklab, #f4fbef 88%, #fff); -} - -.graph-group-node-namespace { - border-color: #e2bcc1; - background: color-mix(in oklab, #fdf4f5 88%, #fff); -} - -.graph-group-label { - position: absolute; - top: 0.52rem; - left: 0.78rem; - border-radius: 0.65rem 0.65rem 0.85rem 0.85rem; - border: 1px solid color-mix(in oklab, #c9ced5 72%, #fff); - background: color-mix(in oklab, #f0f2f5 88%, #fff); - padding: 0.12rem 0.55rem; - font-family: var(--font-mono); - font-size: 0.72rem; - font-weight: 700; - color: #4d5966; -} - -.graph-group-node-file .graph-group-label { - border-color: #98bf84; - background: #d8ebc9; - color: #455b49; -} - -.graph-group-node-namespace .graph-group-label { - border-color: #deafb5; - background: #f0d0d3; - color: #6c4b54; -} - -/* Strip the React Flow wrapper node of all visual styling for bundle nodes */ -.react-flow__node:has(.graph-bundle-node) { - background: transparent !important; - border: none !important; - box-shadow: none !important; - padding: 0 !important; - min-width: 0 !important; - min-height: 0 !important; - width: 6px !important; - height: 6px !important; - pointer-events: none !important; - opacity: 0 !important; -} - -.graph-edge-tooltip { - position: absolute; - pointer-events: none; - border: 1px solid color-mix(in oklab, var(--graph-chrome-border) 88%, #fff); - border-radius: 0.42rem; - background: color-mix(in oklab, #fff 90%, var(--graph-chrome-bg)); - color: #3d4650; - font-family: var(--font-mono); - font-size: 0.61rem; - font-weight: 700; - letter-spacing: 0.01em; - text-transform: lowercase; - white-space: nowrap; - padding: 0.08rem 0.42rem; - box-shadow: 0 6px 12px rgb(20 24 28 / 0.16); -} - -.graph-handle { - width: 6px; - height: 6px; - opacity: 0; - border: none; - background: transparent; -} - -.graph-bundle-handle { - pointer-events: none; -} - -.graph-member-handle { - top: 50%; -} - -.graph-handle-target { - left: -6px; -} - -.graph-member-handle-target { - left: -5px; -} - -.graph-handle-source { - right: -6px; -} - -.graph-handle-top { - top: -6px; -} - -.graph-handle-bottom { - bottom: -6px; -} - -.graph-member-handle-source { - right: -5px; -} - -.graph-hidden-member-handles { - position: absolute; - inset: 0; - pointer-events: none; -} - -.graph-hidden-member-handle-pair { - position: relative; - width: 100%; - height: 0; -} - -.graph-hidden-member-handle { - opacity: 0; - pointer-events: none; -} - -.graph-empty { - margin: 0.7rem; - border: 1px dashed var(--line); - border-radius: 0.86rem; - padding: 1rem; - background: color-mix(in oklab, #fff 64%, oklch(0.89 0.043 95)); - color: var(--muted); -} - -.graph-empty strong { - display: block; - margin-bottom: 0.35rem; - color: color-mix(in oklab, var(--ink) 90%, #0d2438); -} - -.graph-empty p { - margin: 0; -} - -.mermaid-shell { - height: 100%; - overflow: auto; - padding: 1rem; - background: color-mix(in oklab, #fff 88%, #e8eaeb); -} - -.pane-code { - min-height: 0; -} - -.code-occurrence-toolbar { - margin: 0 0.7rem; - border: 1px solid var(--line); - border-radius: 0.74rem; - background: color-mix(in oklab, #fff 90%, oklch(0.9 0.03 95)); - padding: 0.35rem 0.48rem; - display: grid; - grid-template-columns: auto auto auto minmax(0, 1fr); - align-items: center; - gap: 0.38rem; -} - -.code-occurrence-toolbar button { - border: 1px solid var(--line); - border-radius: 0.5rem; - background: #fff; - padding: 0.2rem 0.5rem; - cursor: pointer; -} - -.code-occurrence-toolbar button:disabled { - opacity: 0.58; - cursor: default; -} - -.code-occurrence-summary { - font-family: var(--font-mono); - font-size: 0.68rem; - color: var(--muted); -} - -.code-occurrence-list { - min-width: 0; - display: flex; - gap: 0.22rem; - overflow-x: auto; - overflow-y: hidden; - padding-bottom: 0.08rem; - scrollbar-width: thin; -} - -.code-occurrence-chip { - flex: 0 0 auto; - font-family: var(--font-mono); - font-size: 0.64rem; - border: 1px solid var(--line); - border-radius: 999px; - background: #fff; - padding: 0.1rem 0.44rem; - cursor: pointer; -} - -.code-occurrence-chip.active { - border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); - background: color-mix(in oklab, #fff 78%, oklch(0.88 0.05 219)); -} - -.pane-code-header button { - border: 1px solid var(--line); - border-radius: 0.62rem; - background: #fff; - padding: 0.35rem 0.64rem; - font-weight: 600; - cursor: pointer; -} - -.pane-code-header button:disabled { - opacity: 0.6; - cursor: default; -} - -.node-meta { - margin: 0.7rem; - border: 1px solid var(--line); - border-radius: 0.78rem; - background: #fff; - padding: 0.56rem 0.64rem; - display: grid; - gap: 0.24rem; -} - -.node-meta strong { - margin-right: 0.5rem; -} - -.dirty-pill { - margin-left: 0.45rem; - border: 1px solid color-mix(in oklab, var(--accent) 65%, #5e5d43); - background: color-mix(in oklab, var(--accent) 35%, #fff); - border-radius: 999px; - padding: 0.08rem 0.42rem; - font-size: 0.66rem; - font-weight: 700; -} - -.monaco-shell { - margin: 0 0.7rem 0.7rem; - border: 1px solid var(--line); - border-radius: 0.78rem; - overflow: hidden; - min-height: 16rem; - flex: 1; -} - -.monaco-focus-line { - background: color-mix(in oklab, #f0b429 28%, transparent) !important; -} - -.monaco-focus-range { - background: color-mix(in oklab, #f0b429 26%, transparent) !important; - border-bottom: 1px solid color-mix(in oklab, #f0b429 65%, #8d7d3f); -} - -.monaco-focus-inline { - background: color-mix(in oklab, #f0b429 28%, transparent) !important; -} - -.confirm-overlay { - position: fixed; - inset: 0; - background: rgba(17, 19, 22, 0.42); - display: grid; - place-items: center; - z-index: 50; -} - -.confirm-modal { - width: min(27rem, calc(100vw - 2rem)); - border: 1px solid var(--line); - border-radius: 0.86rem; - background: #fff; - box-shadow: 0 22px 42px rgba(12, 18, 24, 0.24); - padding: 1rem; -} - -.confirm-modal h3 { - margin: 0 0 0.4rem; -} - -.confirm-modal p { - margin: 0; - color: var(--muted); -} - -.confirm-actions { - margin-top: 0.9rem; - display: flex; - justify-content: flex-end; - gap: 0.5rem; -} - -.confirm-actions button { - border: 1px solid var(--line); - border-radius: 0.62rem; - background: #fff; - padding: 0.35rem 0.7rem; - cursor: pointer; -} - -.confirm-actions .confirm-primary { - border-color: color-mix(in oklab, var(--accent) 65%, #5e5d43); - background: color-mix(in oklab, var(--accent) 45%, #fff); - font-weight: 700; -} - -.command-palette-overlay { - position: fixed; - inset: 0; - background: rgb(17 19 22 / 0.38); - display: grid; - place-items: start center; - padding-top: min(18vh, 8rem); - z-index: 72; -} - -.command-palette { - width: min(36rem, calc(100vw - 1.6rem)); - border: 1px solid var(--line); - border-radius: 0.86rem; - background: color-mix(in oklab, #fff 94%, var(--surface-1)); - box-shadow: 0 18px 36px rgb(12 18 24 / 0.24); - padding: 0.72rem; - display: grid; - gap: 0.54rem; -} - -.command-palette label { - font-family: var(--font-mono); - font-size: 0.68rem; - color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.02em; -} - -.command-palette input { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.68rem; - background: #fff; - padding: 0.5rem 0.62rem; -} - -.command-palette input:focus { - outline: 2px solid color-mix(in oklab, var(--focus) 48%, transparent); - outline-offset: 1px; -} - -.command-palette-results { - max-height: min(50vh, 22rem); - overflow: auto; - display: grid; - gap: 0.32rem; - padding-right: 0.14rem; -} - -.command-palette-item { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.62rem; - background: #fff; - text-align: left; - padding: 0.42rem 0.56rem; - cursor: pointer; - display: grid; - gap: 0.08rem; -} - -.command-palette-item span { - font-size: 0.86rem; - font-weight: 700; -} - -.command-palette-item small { - font-size: 0.72rem; - color: var(--muted); -} - -.command-palette-item-active { - border-color: color-mix(in oklab, var(--focus) 50%, var(--line)); - background: color-mix(in oklab, #fff 76%, oklch(0.88 0.05 219)); -} - -.command-palette-item:disabled { - opacity: 0.55; - cursor: default; -} - -.command-palette-empty { - margin: 0; - border: 1px dashed var(--line); - border-radius: 0.62rem; - background: #fff; - color: var(--muted); - padding: 0.58rem; - text-align: center; -} - -.workspace-learn { - grid-template-columns: minmax(340px, 1.15fr) minmax(360px, 1.05fr) minmax(340px, 1fr); -} - -.workspace-debug { - grid-template-columns: minmax(260px, 0.9fr) minmax(560px, 1.6fr) minmax(320px, 1fr); -} - -.workspace-review { - grid-template-columns: minmax(320px, 1fr) minmax(360px, 1fr) minmax(440px, 1.4fr); -} - -.advanced-settings { - margin: 0.68rem; - border-top: 1px solid var(--line); - padding-top: 0.54rem; -} - -.advanced-settings-toggle { - border: 1px solid var(--line); - border-radius: 0.6rem; - background: #fff; - padding: 0.3rem 0.6rem; - font-size: 0.74rem; - cursor: pointer; -} - -.advanced-settings-drawer { - margin-top: 0.56rem; - border: 1px solid var(--line); - border-radius: 0.72rem; - background: color-mix(in oklab, #fff 92%, oklch(0.9 0.03 95)); - overflow: hidden; -} - -.response-answer-cards { - display: grid; - gap: 0.62rem; - padding-bottom: 0.7rem; -} - -.section-card-header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.55rem; - flex-wrap: wrap; -} - -.section-card-header h3, -.section-card-header h4 { - margin: 0; -} - -.section-card-actions { - display: inline-flex; - flex-wrap: wrap; - gap: 0.34rem; -} - -.section-card-actions button { - border: 1px solid var(--line); - border-radius: 0.55rem; - background: #fff; - padding: 0.26rem 0.55rem; - cursor: pointer; -} - -.response-citation-list { - margin: 0; - padding: 0; - list-style: none; - display: grid; - gap: 0.46rem; -} - -.response-citation-item { - border: 1px solid var(--line); - border-radius: 0.62rem; - background: color-mix(in oklab, #fff 90%, oklch(0.91 0.03 95)); - padding: 0.46rem; - display: grid; - gap: 0.34rem; -} - -.response-citation-item button { - border: 1px solid var(--line); - border-radius: 0.5rem; - background: #fff; - padding: 0.24rem 0.52rem; - cursor: pointer; - justify-self: start; -} - -.response-citation-meta { - display: flex; - flex-wrap: wrap; - gap: 0.38rem; - align-items: center; -} - -.shell-section-grid { - width: 100%; - display: grid; - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); - gap: 0.7rem; - align-content: start; -} - -.shell-card { - border: 1px solid var(--line); - border-radius: 0.9rem; - background: color-mix(in oklab, #fff 92%, var(--surface-1)); - box-shadow: 0 10px 20px rgb(17 24 31 / 0.07); - padding: 0.8rem; - display: grid; - gap: 0.48rem; - min-height: 0; -} - -.shell-card h3, -.shell-card h4 { - margin: 0; -} - -.shell-card p { - margin: 0; - color: var(--muted); -} - -.shell-card input, -.shell-card select, -.shell-card textarea, -.shell-card button { - font: inherit; -} - -.shell-card input, -.shell-card select, -.shell-card textarea { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.34rem 0.48rem; -} - -.shell-card button { - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.28rem 0.58rem; - cursor: pointer; -} - -.shell-card ul, -.shell-card ol { - margin: 0; - padding-left: 1.15rem; - display: grid; - gap: 0.34rem; -} - -.shell-card li { - color: color-mix(in oklab, var(--ink) 90%, #111); -} - -.shell-inline-actions { - display: flex; - flex-wrap: wrap; - gap: 0.42rem; -} - -.shell-toggle { - display: inline-flex; - align-items: center; - gap: 0.42rem; -} - -.settings-page { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.9rem; - background: color-mix(in oklab, #fff 92%, var(--surface-1)); - box-shadow: 0 10px 20px rgb(17 24 31 / 0.07); - padding: 0.82rem; - display: grid; - gap: 0.62rem; -} - -.settings-page-header h3 { - margin: 0; -} - -.settings-page-header p { - margin: 0.2rem 0 0; - color: var(--muted); -} - -.settings-groups { - display: grid; - gap: 0.45rem; -} - -.settings-toggle { - display: inline-flex; - align-items: center; - gap: 0.5rem; -} - -.settings-help-card { - border: 1px dashed var(--line); - border-radius: 0.7rem; - padding: 0.55rem; - background: #fff; - display: grid; - gap: 0.18rem; -} - -.settings-help-card h4, -.settings-help-card p { - margin: 0; -} - -.settings-help-card p { - color: var(--muted); -} - -.spaces-panel { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.9rem; - background: color-mix(in oklab, #fff 92%, var(--surface-1)); - box-shadow: 0 10px 20px rgb(17 24 31 / 0.07); - padding: 0.85rem; - display: grid; - gap: 0.62rem; - min-height: 0; -} - -.spaces-panel-header h3 { - margin: 0; -} - -.spaces-panel-header p { - margin: 0.2rem 0 0; - color: var(--muted); -} - -.spaces-create, -.spaces-filter-row { - display: grid; - gap: 0.42rem; -} - -.spaces-create input, -.spaces-create textarea, -.spaces-filter-row input { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.34rem 0.48rem; -} - -.spaces-create button { - width: fit-content; - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.28rem 0.58rem; - cursor: pointer; -} - -.spaces-list { - min-height: 0; - overflow: auto; - display: grid; - gap: 0.46rem; -} - -.spaces-item { - border: 1px solid var(--line); - border-radius: 0.66rem; - background: #fff; - padding: 0.5rem; - display: grid; - gap: 0.34rem; -} - -.spaces-item-active { - border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); - background: color-mix(in oklab, #fff 78%, oklch(0.88 0.05 219)); -} - -.spaces-item h4 { - margin: 0; -} - -.spaces-item p { - margin: 0; - color: var(--muted); -} - -.spaces-item-notes { - font-family: var(--font-mono); - font-size: 0.72rem; -} - -.spaces-item-meta { - display: inline-flex; - gap: 0.5rem; - flex-wrap: wrap; - font-size: 0.72rem; - color: var(--muted); -} - -.spaces-item-actions { - display: inline-flex; - gap: 0.36rem; -} - -.spaces-item-actions button { - border: 1px solid var(--line); - border-radius: 0.5rem; - background: #fff; - padding: 0.22rem 0.48rem; - cursor: pointer; -} - -.spaces-empty { - border: 1px dashed var(--line); - border-radius: 0.6rem; - padding: 0.6rem; - text-align: center; - color: var(--muted); -} - -.bookmark-manager-overlay { - position: fixed; - inset: 0; - background: rgb(17 19 22 / 0.42); - display: grid; - place-items: center; - z-index: 65; -} - -.bookmark-manager { - width: min(70rem, calc(100vw - 1.6rem)); - max-height: calc(100vh - 1.6rem); - border: 1px solid var(--line); - border-radius: 0.86rem; - background: #fff; - box-shadow: 0 22px 42px rgb(12 18 24 / 0.24); - padding: 0.9rem; - display: grid; - gap: 0.62rem; - overflow: auto; -} - -.bookmark-manager-header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.5rem; -} - -.bookmark-manager-header h3 { - margin: 0; -} - -.bookmark-manager-header button { - border: 1px solid var(--line); - border-radius: 0.56rem; - background: #fff; - padding: 0.22rem 0.58rem; - cursor: pointer; -} - -.bookmark-manager-columns { - display: grid; - grid-template-columns: minmax(240px, 1fr) minmax(380px, 1.4fr); - gap: 0.62rem; - min-height: 0; -} - -.bookmark-section { - border: 1px solid var(--line); - border-radius: 0.72rem; - background: color-mix(in oklab, #fff 94%, oklch(0.9 0.02 95)); - padding: 0.56rem; - display: grid; - gap: 0.46rem; - min-height: 0; -} - -.bookmark-section h4 { - margin: 0; - font-size: 0.84rem; -} - -.bookmark-inline-row { - display: flex; - gap: 0.3rem; - align-items: center; -} - -.bookmark-inline-row input, -.bookmark-inline-row select, -.bookmark-seed-card textarea, -.bookmark-item textarea, -.bookmark-category-row input { - width: 100%; - border: 1px solid var(--line); - border-radius: 0.5rem; - background: #fff; - min-height: 1.85rem; - padding: 0.22rem 0.44rem; -} - -.bookmark-inline-row button, -.bookmark-item button, -.bookmark-category-row button, -.bookmark-seed-card button { - border: 1px solid var(--line); - border-radius: 0.48rem; - background: #fff; - padding: 0.18rem 0.52rem; - cursor: pointer; - font-size: 0.72rem; -} - -.bookmark-category-filter { - display: flex; - flex-wrap: wrap; - gap: 0.26rem; -} - -.bookmark-category-filter button { - border: 1px solid var(--line); - border-radius: 999px; - background: #fff; - padding: 0.12rem 0.5rem; - font-size: 0.68rem; - cursor: pointer; -} - -.bookmark-category-filter .bookmark-active { - border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); - background: color-mix(in oklab, #fff 80%, oklch(0.88 0.05 219)); -} - -.bookmark-list { - display: grid; - gap: 0.34rem; - overflow: auto; - min-height: 0; -} - -.bookmark-category-row { - display: grid; - grid-template-columns: minmax(0, 1fr) auto auto; - gap: 0.24rem; -} - -.bookmark-seed-card { - border: 1px solid var(--line); - border-radius: 0.62rem; - background: #fff; - padding: 0.5rem; - display: grid; - gap: 0.34rem; -} - -.bookmark-seed-title { - font-size: 0.72rem; - text-transform: uppercase; - color: var(--muted); - font-family: var(--font-mono); -} - -.bookmark-seed-label { - font-weight: 700; - font-size: 0.84rem; -} - -.bookmark-item { - border: 1px solid var(--line); - border-radius: 0.62rem; - background: #fff; - padding: 0.46rem; - display: grid; - gap: 0.3rem; -} - -.bookmark-node-link { - border: none; - background: transparent; - text-align: left; - padding: 0; - color: color-mix(in oklab, var(--ink) 90%, #08203b); - font-weight: 700; - cursor: pointer; -} - -.bookmark-node-link:hover { - text-decoration: underline; -} - -.bookmark-empty { - border: 1px dashed var(--line); - border-radius: 0.56rem; - background: #fff; - color: var(--muted); - padding: 0.7rem; - text-align: center; - font-size: 0.76rem; -} - -@media (max-width: 700px) { - .app-body { - grid-template-columns: 1fr; - padding: var(--space-2); - } - - .app-nav { - padding: var(--space-3); - } - - .app-nav-links { - grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); - } - - .topbar { - padding: 0.8rem var(--space-3); - } - - .status-strip { - padding: 0.45rem var(--space-3); - } - - .investigate-toolbar { - align-items: stretch; - } - - .investigate-toolbar-actions { - width: 100%; - justify-content: flex-start; - } - - .focus-switcher { - width: 100%; - justify-content: space-between; - } - - .agent-connection-settings { - grid-template-columns: 1fr; - } - - .explorer-toolbar-row { - font-size: 0.72rem; - } - - .explorer-clear-button { - margin-left: 0; - } -} - -@media (max-width: 1200px) { - .app-body { - grid-template-columns: 1fr; - } - - .app-nav-links { - grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); - } - - .workspace { - grid-template-columns: 1fr; - grid-template-rows: minmax(320px, auto) minmax(420px, 1fr) minmax(360px, auto); - } - - .investigate-pane { - min-height: 60vh; - max-height: none; - } - - .path-input { - min-width: 11rem; - } - - .graph-header { - grid-template-columns: 1fr; - align-items: stretch; - } - - .graph-trail-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .trail-dialog-grid, - .trail-dialog-grid-secondary, - .trail-filter-columns { - grid-template-columns: 1fr; - } - - .bookmark-manager-columns { - grid-template-columns: 1fr; - } -} - -@media (prefers-reduced-motion: reduce) { - *, - *::before, - *::after { - animation-duration: 1ms !important; - animation-iteration-count: 1 !important; - transition-duration: 1ms !important; - scroll-behavior: auto !important; - } -} +@import "./theme/tokens.css"; +@import "./theme/base.css"; +@import "./theme/legacy.css"; +@import "./theme/components.css"; +@import "./theme/graph.css"; diff --git a/codestory-ui/src/theme/base.css b/codestory-ui/src/theme/base.css new file mode 100644 index 0000000..117fc53 --- /dev/null +++ b/codestory-ui/src/theme/base.css @@ -0,0 +1,94 @@ +* { + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; +} + +body { + margin: 0; + min-height: 100vh; + min-height: 100dvh; + font-family: var(--font-body); + color: var(--color-foreground); + background: + radial-gradient( + circle at 8% 10%, + color-mix(in oklab, var(--color-tertiary) 34%, transparent), + transparent 28% + ), + radial-gradient( + circle at 86% 16%, + color-mix(in oklab, var(--color-secondary) 25%, transparent), + transparent 35% + ), + radial-gradient( + circle at 96% 92%, + color-mix(in oklab, var(--color-quaternary) 26%, transparent), + transparent 34% + ), + radial-gradient(var(--color-border) 1px, transparent 1px), + linear-gradient(180deg, #fffdf5 0%, #fff8e7 100%); + background-size: + auto, + auto, + auto, + 22px 22px, + auto; + background-position: + center, + center, + center, + 0 0, + center; + overflow: auto; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: var(--font-heading); + letter-spacing: -0.02em; +} + +button, +input, +textarea, +select { + font: inherit; +} + +button, +input, +textarea, +select, +[role="button"] { + min-height: 2.75rem; +} + +@media (max-width: 700px) { + button, + input, + textarea, + select, + [role="button"] { + min-height: 3rem; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 1ms !important; + animation-iteration-count: 1 !important; + transition-duration: 1ms !important; + scroll-behavior: auto !important; + } +} diff --git a/codestory-ui/src/theme/components.css b/codestory-ui/src/theme/components.css new file mode 100644 index 0000000..6bb3fb5 --- /dev/null +++ b/codestory-ui/src/theme/components.css @@ -0,0 +1,442 @@ +.ui-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.45rem; + padding: 0.5rem 0.95rem; + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-full); + font-family: var(--font-heading); + font-weight: 700; + text-decoration: none; + cursor: pointer; + transition: + transform var(--duration-medium) var(--ease-playful), + box-shadow var(--duration-medium) var(--ease-playful), + background-color var(--duration-fast) ease, + color var(--duration-fast) ease; +} + +.ui-button svg { + flex-shrink: 0; +} + +.ui-button:focus-visible, +.ui-input:focus-visible, +.ui-select:focus-visible, +.ui-textarea:focus-visible, +.path-input:focus-visible, +.graph-search-input:focus-visible, +.command-palette input:focus-visible { + outline: 3px solid color-mix(in oklab, var(--color-ring) 60%, transparent); + outline-offset: 2px; +} + +.ui-button-primary { + background: var(--color-accent); + color: var(--color-accent-foreground); + box-shadow: var(--shadow-pop); +} + +.ui-button-secondary { + background: white; + color: var(--color-foreground); + box-shadow: none; +} + +.ui-button-ghost { + background: color-mix(in oklab, var(--color-muted) 60%, white); + color: var(--color-foreground); + box-shadow: none; +} + +.ui-button:hover:not(:disabled), +.topbar-actions button:hover:not(:disabled), +.investigate-toolbar-actions button:hover:not(:disabled), +.graph-trail-toolbar button:hover:not(:disabled), +.graph-zoom-panel button:hover, +.graph-legend-toggle-panel button:hover, +.command-palette-item:hover:not(:disabled), +.bookmark-inline-row button:hover, +.bookmark-item button:hover, +.bookmark-category-row button:hover, +.bookmark-seed-card button:hover, +.spaces-item-actions button:hover { + transform: translate(-2px, -2px); + box-shadow: var(--shadow-pop-hover); +} + +.ui-button:active:not(:disabled), +.topbar-actions button:active:not(:disabled), +.investigate-toolbar-actions button:active:not(:disabled), +.graph-trail-toolbar button:active:not(:disabled), +.command-palette-item:active:not(:disabled), +.spaces-item-actions button:active { + transform: translate(2px, 2px); + box-shadow: var(--shadow-pop-active); +} + +.ui-button:disabled, +.topbar-actions button:disabled, +.investigate-toolbar-actions button:disabled, +.graph-trail-toolbar button:disabled, +.spaces-item-actions button:disabled, +.command-palette-item:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +.ui-card, +.pane, +.card, +.app-nav, +.graph-trail-controls, +.command-palette, +.bookmark-manager, +.spaces-item, +.starter-card, +.settings-help-card, +.settings-toggle, +.spaces-create, +.spaces-filter-row, +.graph-context-menu, +.app-placeholder-card { + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-md); + background: var(--color-card); + box-shadow: var(--shadow-pop); +} + +.ui-card-accent { + background: color-mix(in oklab, white 82%, var(--color-accent)); +} + +.ui-card-secondary { + background: color-mix(in oklab, white 82%, var(--color-secondary)); +} + +.ui-card-tertiary { + background: color-mix(in oklab, white 80%, var(--color-tertiary)); +} + +.ui-panel, +.pane { + border-radius: var(--radius-lg); +} + +.ui-input-field { + display: grid; + gap: 0.3rem; +} + +.ui-input-label { + font-family: var(--font-heading); + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.04em; + font-weight: 700; +} + +.ui-input-hint { + color: var(--color-muted-foreground); + font-size: 0.7rem; +} + +.ui-badge, +.starter-chip, +.kind-pill, +.graph-chip, +.focus-switcher, +.focus-switcher-item, +.tabs button, +.graph-tabs button, +.tree-duplicate-pill, +.graph-pill-duplicate-count, +.command-palette-empty, +.bookmark-category-filter button, +.bookmark-active { + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-full); + background: white; + box-shadow: 2px 2px 0 0 color-mix(in oklab, var(--color-shadow) 50%, transparent); +} + +.ui-input, +.ui-select, +.ui-textarea, +.path-input, +.graph-search-input, +.command-palette input, +.topbar-actions input, +.spaces-create input, +.spaces-create textarea, +.spaces-filter-row input, +.graph-control-field select, +.graph-control-field input, +.bookmark-inline-row input, +.bookmark-inline-row select, +.bookmark-seed-card textarea, +.bookmark-item textarea, +.bookmark-category-row input { + border: var(--border-width) solid + color-mix(in oklab, var(--color-border) 30%, var(--color-shadow)); + border-radius: var(--radius-sm); + background: var(--color-input); + color: var(--color-foreground); +} + +.topbar, +.status-strip, +.investigate-toolbar, +.pane-header, +.bookmark-manager-header, +.spaces-panel-header, +.settings-page-header { + background: linear-gradient( + 140deg, + color-mix(in oklab, white 70%, var(--color-tertiary)), + color-mix(in oklab, white 78%, var(--color-secondary)) + ); +} + +.brand h1, +.app-nav h2, +.pane-header h2, +.starter-header h2, +.settings-page-header h3 { + font-weight: 800; +} + +.brand h1 { + font-size: 1.72rem; +} + +.brand p { + font-size: 0.92rem; +} + +.app-nav-link span, +.starter-header h2, +.settings-page-header h3 { + display: inline-flex; + align-items: center; + gap: 0.35rem; +} + +.topbar-actions button, +.investigate-toolbar-actions button, +.graph-trail-toolbar button, +.spaces-item-actions button, +.command-palette-item, +.bookmark-inline-row button, +.bookmark-item button, +.bookmark-category-row button, +.bookmark-seed-card button, +.app-placeholder-card button, +.trail-dialog-actions button { + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-full); + background: white; + box-shadow: var(--shadow-pop); + font-family: var(--font-heading); + font-weight: 700; +} + +.topbar-actions button:first-of-type, +.graph-trail-toolbar button:first-of-type, +.starter-primary, +.confirm-actions .confirm-primary, +.command-palette-item-active, +.bookmark-category-filter .bookmark-active, +.spaces-item-active, +.focus-switcher-item-active, +.graph-chip-active, +.tab-active { + background: var(--color-accent) !important; + border-color: var(--color-shadow) !important; + color: white !important; +} + +.status-strip, +.brand p, +.app-nav p, +.starter-help p, +.tree-path, +.graph-empty, +.bookmark-empty, +.command-palette label, +.command-palette-item small, +.settings-page-header p, +.settings-help-card p, +.spaces-item-meta, +.spaces-empty { + color: var(--color-muted-foreground); +} + +.settings-toggle { + display: grid; + gap: 0.4rem; + padding: 0.85rem 1rem; + border-radius: var(--radius-md); + box-shadow: 3px 3px 0 0 var(--color-shadow); +} + +.settings-toggle p, +.settings-help-card p { + margin: 0; +} + +.settings-toggle .ui-badge { + justify-self: start; + width: auto; +} + +.settings-toggle h4, +.settings-help-card h4 { + margin: 0; + display: inline-flex; + align-items: center; + gap: 0.35rem; +} + +.spaces-filter-row { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.spaces-filter-row svg { + color: var(--color-muted-foreground); +} + +.status-strip { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + font-weight: 500; +} + +.status-strip > span:first-child { + font-family: var(--font-heading); + font-size: 0.95rem; + color: color-mix(in oklab, var(--color-foreground) 80%, var(--color-ring)); +} + +.status-strip > span:last-child { + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-full); + padding: 0.25rem 0.6rem; + background: color-mix(in oklab, white 64%, var(--color-quaternary)); + box-shadow: 2px 2px 0 0 color-mix(in oklab, var(--color-shadow) 55%, transparent); + font-family: var(--font-heading); + font-size: 0.8rem; +} + +.app-nav-link.ui-button { + justify-content: flex-start; + border-radius: var(--radius-md); + font-family: var(--font-body); + font-weight: 600; + padding: 0.5rem 0.65rem; + box-shadow: 2px 2px 0 0 color-mix(in oklab, var(--color-shadow) 50%, transparent); + min-height: 0; +} + +.app-nav-link span { + font-size: 0.92rem; + font-weight: 800; +} + +.app-nav-link small { + font-size: 0.74rem; +} + +.focus-switcher { + padding: 0.3rem; + box-shadow: var(--shadow-pop); +} + +.focus-switcher .focus-switcher-item.ui-button { + min-height: 2.2rem; + padding: 0.34rem 0.8rem; + font-family: var(--font-heading); +} + +.pane-header h2 { + font-size: 1rem; +} + +.settings-groups { + display: grid; + gap: 0.7rem; + grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); +} + +.settings-help-card { + margin-top: 0.75rem; + padding: 0.8rem 0.95rem; +} + +.settings-page { + width: 100%; +} + +.tree-node-active .tree-label, +.graph-node-selected, +.graph-floating-pill-selected, +.graph-member-chip-focused, +.graph-context-menu button:focus-visible, +.command-palette-item-active { + border-color: var(--color-ring) !important; +} + +.app-nav-link-active, +.starter-chip-ready, +.graph-node-file, +.graph-node-center { + background: color-mix(in oklab, white 72%, var(--color-quaternary)); +} + +.investigate-toolbar-actions button:first-child, +.spaces-create button, +.spaces-item-actions button:first-child, +.section-card-actions button, +.graph-links button { + background: var(--color-tertiary); +} + +.investigate-toolbar-actions button:last-child, +.spaces-item-actions button:last-child, +.confirm-actions button, +.starter-dismiss, +.starter-help-toggle { + background: var(--color-secondary); + color: white; +} + +.starter-dismiss, +.starter-help-toggle { + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-full); + box-shadow: var(--shadow-pop); + padding: 0.25rem 0.55rem; +} + +@media (max-width: 1200px) { + .pane, + .card, + .app-nav, + .graph-trail-controls, + .bookmark-manager, + .command-palette, + .spaces-item, + .settings-help-card, + .settings-toggle, + .spaces-create, + .spaces-filter-row { + box-shadow: 2px 2px 0 0 var(--color-shadow); + } +} diff --git a/codestory-ui/src/theme/graph.css b/codestory-ui/src/theme/graph.css new file mode 100644 index 0000000..a4f928a --- /dev/null +++ b/codestory-ui/src/theme/graph.css @@ -0,0 +1,141 @@ +.graph-canvas { + background: + radial-gradient( + circle at 10% 12%, + color-mix(in oklab, var(--color-tertiary) 30%, transparent), + transparent 30% + ), + radial-gradient( + circle at 92% 16%, + color-mix(in oklab, var(--color-secondary) 30%, transparent), + transparent 34% + ), + linear-gradient(180deg, var(--graph-canvas-top), var(--graph-canvas-bottom)); +} + +.graph-flow-shell, +.react-flow, +.react-flow__renderer, +.react-flow__pane { + background: transparent; +} + +.graph-node, +.graph-floating-pill, +.graph-group-node, +.graph-trail-controls, +.graph-context-menu, +.graph-legend-panel, +.graph-minimap, +.graph-zoom-panel, +.graph-legend-toggle-panel, +.trail-dialog, +.trail-target-placeholder, +.search-dropdown { + border: var(--border-width) solid var(--color-shadow); + box-shadow: var(--shadow-pop); +} + +.graph-node, +.graph-floating-pill, +.graph-group-node, +.graph-target-clear, +.graph-control-field select, +.graph-control-field input, +.graph-chip, +.graph-trail-toolbar button, +.graph-tabs button, +.search-hit, +.trail-filter-item, +.trail-filter-actions button, +.trail-dialog-actions button { + transition: + transform var(--duration-medium) var(--ease-playful), + box-shadow var(--duration-medium) var(--ease-playful), + border-color var(--duration-fast) ease, + background-color var(--duration-fast) ease; +} + +.graph-node:hover, +.graph-floating-pill:hover, +.graph-group-node:hover, +.search-hit:hover, +.graph-chip:hover, +.trail-filter-actions button:hover, +.trail-dialog-actions button:hover, +.graph-tabs button:hover { + transform: translate(-1px, -1px) rotate(-0.3deg); + box-shadow: var(--shadow-pop-hover); +} + +.graph-node-file-tab { + background: color-mix(in oklab, white 30%, var(--color-tertiary)); +} + +.graph-member-chip-public { + background: color-mix(in oklab, white 50%, var(--color-quaternary)); +} + +.graph-member-chip-private { + background: color-mix(in oklab, white 62%, var(--color-secondary)); +} + +.graph-member-chip-focused, +.graph-floating-pill-selected, +.graph-node-selected, +.search-hit-active, +.graph-legend-row-active { + border-color: var(--color-ring) !important; + box-shadow: + 0 0 0 2px color-mix(in oklab, var(--color-ring) 45%, transparent), + var(--shadow-pop); +} + +.graph-edge-tooltip { + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-full); + background: var(--color-accent); + color: white; + box-shadow: 3px 3px 0 0 var(--color-shadow); +} + +.truncation-pill, +.graph-node-count, +.graph-node-section-count, +.graph-legend-count, +.trail-range-value { + border: var(--border-width) solid var(--color-shadow); + border-radius: var(--radius-full); + background: var(--color-tertiary); + color: var(--color-foreground); + box-shadow: 2px 2px 0 0 var(--color-shadow); +} + +.trail-dialog-backdrop, +.command-palette-overlay, +.bookmark-manager-overlay { + background: rgb(30 41 59 / 0.42); +} + +.graph-legend-line { + border-radius: var(--radius-full); +} + +.graph-empty { + border: var(--border-width) dashed var(--color-shadow); + border-radius: var(--radius-md); + background: color-mix(in oklab, white 80%, var(--color-muted)); +} + +@media (max-width: 1200px) { + .graph-node, + .graph-floating-pill, + .graph-group-node, + .graph-context-menu, + .graph-legend-panel, + .graph-minimap, + .trail-dialog, + .search-dropdown { + box-shadow: 2px 2px 0 0 var(--color-shadow); + } +} diff --git a/codestory-ui/src/theme/legacy.css b/codestory-ui/src/theme/legacy.css new file mode 100644 index 0000000..9a8f548 --- /dev/null +++ b/codestory-ui/src/theme/legacy.css @@ -0,0 +1,2888 @@ +:root { + --font-ui: "Space Grotesk", "Segoe UI", sans-serif; + --font-mono: "JetBrains Mono", "Consolas", monospace; + --bg: oklch(0.93 0.004 95); + --bg-elevated: oklch(0.975 0.002 95); + --ink: oklch(0.28 0.01 250); + --muted: oklch(0.54 0.016 248); + --line: oklch(0.84 0.006 95); + --accent: oklch(0.79 0.14 89); + --focus: oklch(0.73 0.12 220); + --graph-canvas-top: oklch(0.975 0.002 95); + --graph-canvas-bottom: oklch(0.95 0.004 95); + --graph-chrome-bg: oklch(0.96 0.003 95 / 0.9); + --graph-chrome-border: oklch(0.85 0.005 95); + --graph-node-shell: oklch(0.92 0.002 95); + --graph-node-shell-border: oklch(0.82 0.003 95); + --graph-node-core: oklch(1 0 95); + --graph-node-core-border: oklch(0.88 0.003 95); + --graph-file-accent: oklch(0.83 0.06 135); + --graph-public-chip: oklch(0.91 0.12 86); + --graph-public-chip-border: oklch(0.82 0.08 86); + --graph-private-chip: oklch(0.92 0.06 235); + --graph-private-chip-border: oklch(0.84 0.06 235); + --surface-1: oklch(0.975 0.002 95 / 0.92); + --surface-2: oklch(0.965 0.004 96 / 0.94); + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.25rem; + --duration-fast: 140ms; + --duration-medium: 220ms; +} + +* { + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; +} + +body { + margin: 0; + min-height: 100vh; + min-height: 100dvh; + font-family: var(--font-ui); + color: var(--ink); + background: + radial-gradient(circle at 10% 10%, oklch(0.9 0.018 101 / 0.75), transparent 38%), + radial-gradient(circle at 88% 24%, oklch(0.9 0.015 234 / 0.5), transparent 41%), + linear-gradient(180deg, oklch(0.94 0.004 95), oklch(0.925 0.004 94)); + overflow: auto; +} + +button, +input, +textarea { + font: inherit; +} + +.app-shell { + min-height: 100vh; + min-height: 100dvh; + min-height: 0; + display: grid; + grid-template-rows: auto auto minmax(0, 1fr); + overflow: auto; +} + +.app-body { + width: min(100%, 120rem); + margin: 0 auto; + min-height: 0; + display: grid; + grid-template-columns: minmax(220px, 260px) minmax(0, 1fr); + gap: var(--space-4); + padding: var(--space-3); + overflow: visible; +} + +.app-nav { + min-height: 0; + border: 1px solid var(--line); + border-radius: 0.95rem; + background: linear-gradient( + 160deg, + color-mix(in oklab, var(--surface-1) 90%, #fff), + color-mix(in oklab, var(--surface-2) 82%, #fff) + ); + box-shadow: 0 10px 20px rgb(17 24 31 / 0.08); + padding: var(--space-4); + display: grid; + grid-template-rows: auto auto minmax(0, 1fr); + gap: var(--space-3); +} + +.app-nav h2 { + margin: 0; + font-size: 1rem; +} + +.app-nav p { + margin: 0; + color: var(--muted); + font-size: 0.78rem; +} + +.app-nav-links { + min-height: 0; + overflow: auto; + display: grid; + gap: 0.35rem; + align-content: start; +} + +.app-nav-link { + border: 1px solid var(--line); + border-radius: 0.72rem; + background: color-mix(in oklab, #fff 92%, var(--surface-1)); + padding: 0.48rem 0.56rem; + text-align: left; + display: grid; + gap: 0.15rem; + cursor: pointer; + transition: + transform var(--duration-fast) ease, + border-color var(--duration-medium) ease, + background var(--duration-medium) ease; +} + +.app-nav-link:hover { + transform: translateY(-1px); + border-color: color-mix(in oklab, var(--focus) 34%, var(--line)); +} + +.app-nav-link span { + font-size: 0.84rem; + font-weight: 700; + color: var(--ink); +} + +.app-nav-link small { + color: var(--muted); + font-size: 0.7rem; +} + +.app-nav-link-active { + border-color: color-mix(in oklab, var(--focus) 48%, var(--line)); + background: color-mix(in oklab, #fff 74%, oklch(0.87 0.05 219)); +} + +.app-content { + min-height: 0; + overflow: auto; + display: flex; +} + +.app-placeholder-card { + width: 100%; + border: 1px solid var(--line); + border-radius: 1rem; + background: color-mix(in oklab, #fff 88%, var(--surface-1)); + display: grid; + place-content: center; + gap: 0.6rem; + text-align: center; + padding: 1.25rem; + box-shadow: 0 10px 20px rgb(17 24 31 / 0.08); +} + +.app-placeholder-card h3 { + margin: 0; +} + +.app-placeholder-card p { + margin: 0; + color: var(--muted); + max-width: 34rem; +} + +.app-placeholder-card button { + justify-self: center; + border: 1px solid var(--line); + border-radius: 0.65rem; + background: #fff; + padding: 0.38rem 0.72rem; + cursor: pointer; +} + +.topbar { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + padding: 0.9rem var(--space-5); + border-bottom: 1px solid var(--line); + background: color-mix(in oklab, var(--bg-elevated) 96%, #fff); + backdrop-filter: blur(8px); +} + +.brand h1 { + margin: 0; + line-height: 1; + font-size: 1.3rem; +} + +.brand p { + margin: 0.24rem 0 0; + color: var(--muted); + font-size: 0.86rem; +} + +.topbar-actions { + display: flex; + gap: 0.5rem; + align-items: center; + flex-wrap: wrap; +} + +.topbar-actions button { + border: 1px solid color-mix(in oklab, var(--line) 70%, #0000); + border-radius: 0.62rem; + background: #fff; + padding: 0.48rem 0.74rem; + font-weight: 600; + cursor: pointer; + transition: + border-color 180ms ease, + transform 180ms ease; +} + +.topbar-actions button:hover { + transform: translateY(-1px); + border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); +} + +.topbar-actions button:disabled { + opacity: 0.58; + cursor: not-allowed; + transform: none; +} + +.path-input { + min-width: 16rem; + border: 1px solid var(--line); + border-radius: 0.65rem; + padding: 0.48rem 0.62rem; + background: #fff; +} + +.status-strip { + display: flex; + justify-content: space-between; + gap: 0.7rem; + padding: 0.5rem var(--space-5); + border-bottom: 1px solid var(--line); + color: var(--muted); + font-size: 0.88rem; + background: color-mix(in oklab, #fff 88%, oklch(0.86 0.045 92)); +} + +.workspace { + display: grid; + grid-template-columns: minmax(300px, 1fr) minmax(420px, 1.25fr) minmax(360px, 1.05fr); + gap: 0.74rem; + padding: 0; + min-height: 0; + overflow: hidden; + width: 100%; +} + +.investigate-layout { + width: 100%; + min-height: 0; + display: grid; + grid-template-rows: auto auto minmax(0, 1fr); + gap: var(--space-3); +} + +.investigate-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-3); + flex-wrap: wrap; + border: 1px solid var(--line); + border-radius: 0.85rem; + background: color-mix(in oklab, #fff 92%, var(--surface-1)); + padding: 0.5rem 0.6rem; +} + +.investigate-toolbar-actions { + display: inline-flex; + align-items: center; + gap: 0.4rem; +} + +.investigate-toolbar-actions button { + border: 1px solid var(--line); + border-radius: 0.55rem; + background: #fff; + padding: 0.35rem 0.6rem; + cursor: pointer; +} + +.investigate-pane { + min-height: min(68vh, 56rem); + max-height: min(74vh, 60rem); + overflow: hidden; + display: flex; +} + +.investigate-pane > .pane { + width: 100%; +} + +.focus-switcher { + display: inline-flex; + align-items: center; + border: 1px solid var(--line); + border-radius: 999px; + background: #fff; + padding: 0.16rem; + gap: 0.2rem; +} + +.focus-switcher-item { + border: none; + border-radius: 999px; + background: transparent; + color: var(--muted); + padding: 0.34rem 0.72rem; + font-size: 0.8rem; + font-weight: 600; + cursor: pointer; +} + +.focus-switcher-item-active { + color: var(--ink); + background: color-mix(in oklab, #fff 78%, oklch(0.86 0.05 219)); +} + +.starter-card { + border: 1px solid var(--line); + border-radius: 0.9rem; + background: color-mix(in oklab, #fff 92%, var(--surface-1)); + box-shadow: 0 8px 18px rgb(17 24 31 / 0.06); + padding: 0.75rem; + display: grid; + gap: 0.5rem; +} + +.starter-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; +} + +.starter-header h2 { + margin: 0; + font-size: 0.95rem; +} + +.starter-dismiss { + border: none; + background: transparent; + color: var(--muted); + cursor: pointer; +} + +.starter-status-chips { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; +} + +.starter-chip { + border: 1px solid var(--line); + border-radius: 999px; + padding: 0.2rem 0.56rem; + font-size: 0.72rem; + color: var(--muted); + background: #fff; +} + +.starter-chip-ready { + color: color-mix(in oklab, var(--ink) 85%, #124e2a); + border-color: color-mix(in oklab, var(--line) 55%, oklch(0.74 0.08 145)); + background: color-mix(in oklab, #fff 84%, oklch(0.92 0.05 145)); +} + +.starter-next-step { + display: grid; + gap: 0.22rem; +} + +.starter-next-step p { + margin: 0; + color: var(--muted); + font-size: 0.8rem; +} + +.starter-primary { + justify-self: start; + border: 1px solid color-mix(in oklab, var(--line) 45%, var(--focus)); + border-radius: 0.56rem; + background: color-mix(in oklab, #fff 75%, oklch(0.87 0.05 219)); + color: var(--ink); + padding: 0.35rem 0.72rem; + cursor: pointer; + font-weight: 600; +} + +.starter-help-toggle { + justify-self: start; + border: none; + background: transparent; + color: var(--muted); + cursor: pointer; + padding: 0; +} + +.starter-help { + border: 1px dashed var(--line); + border-radius: 0.66rem; + background: #fff; + padding: 0.48rem 0.56rem; +} + +.starter-help p { + margin: 0; + color: var(--muted); + font-size: 0.78rem; +} + +.pane { + min-height: 0; + max-height: 100%; + border: 1px solid var(--line); + border-radius: 0.95rem; + background: color-mix(in oklab, var(--bg-elevated) 95%, #fff); + box-shadow: 0 10px 22px rgba(18, 24, 28, 0.08); + display: flex; + flex-direction: column; + overflow: hidden; +} + +.pane-header { + padding: 0.65rem 0.75rem; + border-bottom: 1px solid var(--line); + display: flex; + justify-content: space-between; + gap: 0.5rem; + align-items: center; +} + +.pane-header h2 { + margin: 0; + font-size: 0.92rem; + letter-spacing: 0.01em; +} + +.tabs, +.graph-tabs { + display: flex; + gap: 0.35rem; + flex-wrap: wrap; +} + +.tabs button, +.graph-tabs button { + border: 1px solid var(--line); + border-radius: 999px; + padding: 0.3rem 0.55rem; + background: #fff; + font-size: 0.76rem; + cursor: pointer; +} + +.tab-active { + background: var(--accent) !important; + border-color: color-mix(in oklab, var(--accent) 60%, #393939) !important; +} + +.pane-response { + overflow: auto; +} + +.prompt-box, +.card { + margin: 0.7rem; + border: 1px solid var(--line); + border-radius: 0.86rem; + background: #fff; +} + +.prompt-box textarea { + width: 100%; + min-height: 6.8rem; + resize: vertical; + border: none; + outline: none; + border-radius: 0.86rem 0.86rem 0 0; + padding: 0.75rem; + background: #fff; +} + +.agent-connection-settings { + display: grid; + grid-template-columns: minmax(7rem, 11rem) minmax(0, 1fr); + gap: 0.5rem; + padding: 0.52rem 0.7rem; + border-top: 1px solid var(--line); + background: color-mix(in oklab, #fff 88%, oklch(0.91 0.03 95)); +} + +.agent-connection-field { + min-width: 0; + display: grid; + gap: 0.2rem; +} + +.agent-connection-field span { + font-family: var(--font-mono); + font-size: 0.66rem; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.agent-connection-field select, +.agent-connection-field input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.5rem; + background: #fff; + min-height: 1.85rem; + padding: 0.24rem 0.46rem; +} + +.retrieval-profile-settings { + display: grid; + gap: 0.5rem; + padding: 0.52rem 0.7rem; + border-top: 1px solid var(--line); + background: color-mix(in oklab, #fff 90%, oklch(0.9 0.04 95)); +} + +.custom-profile-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); + gap: 0.48rem; +} + +.agent-connection-field-wide { + grid-column: 1 / -1; +} + +.profile-checkbox { + display: inline-flex; + align-items: center; + gap: 0.35rem; + color: var(--muted); + font-size: 0.75rem; +} + +.prompt-actions { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.65rem; + border-top: 1px solid var(--line); + padding: 0.54rem 0.72rem; + background: color-mix(in oklab, #fff 85%, oklch(0.89 0.05 95)); +} + +.prompt-actions-meta { + color: var(--muted); + font-size: 0.74rem; +} + +.prompt-actions button, +.graph-links button, +.tree-label { + border: 1px solid var(--line); + border-radius: 0.64rem; + background: #fff; + padding: 0.33rem 0.62rem; + cursor: pointer; +} + +.card { + padding: 0.62rem; +} + +.card h3, +.card h4 { + margin: 0 0 0.52rem; +} + +.section-block { + border-top: 1px solid var(--line); + padding-top: 0.58rem; + margin-top: 0.58rem; +} + +.section-block-content { + display: grid; + gap: 0.5rem; +} + +.response-block { + min-width: 0; +} + +.section-markdown { + margin: 0; + white-space: pre-wrap; + font-family: var(--font-mono); + font-size: 0.76rem; + color: color-mix(in oklab, var(--ink) 90%, #000 9%); + background: color-mix(in oklab, #fff 82%, oklch(0.88 0.045 95)); + border: 1px solid var(--line); + border-radius: 0.68rem; + padding: 0.58rem; +} + +.inline-mermaid-block { + border: 1px solid var(--line); + border-radius: 0.68rem; + background: color-mix(in oklab, #fff 88%, #e8eaeb); + overflow: hidden; +} + +.inline-mermaid { + max-height: 22rem; + padding: 0.75rem; +} + +.graph-links { + display: flex; + gap: 0.35rem; + flex-wrap: wrap; + margin-top: 0.52rem; +} + +.trace-panel { + margin-top: 0.65rem; + border: 1px solid var(--line); + border-radius: 0.68rem; + padding: 0.52rem; + background: color-mix(in oklab, #fff 90%, oklch(0.9 0.04 95)); +} + +.trace-panel summary { + cursor: pointer; + font-family: var(--font-mono); + font-size: 0.72rem; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.trace-panel pre { + margin: 0.5rem 0 0; + white-space: pre-wrap; + font-family: var(--font-mono); + font-size: 0.7rem; + color: color-mix(in oklab, var(--ink) 90%, #000 9%); +} + +.explorer-card { + min-height: 16rem; + display: flex; + flex-direction: column; + gap: 0.55rem; +} + +.explorer-card p { + margin: 0; + color: var(--muted); +} + +.explorer-toolbar { + border: 1px solid var(--line); + border-radius: 0.68rem; + padding: 0.48rem 0.52rem; + display: grid; + gap: 0.44rem; + background: color-mix(in oklab, #fff 86%, oklch(0.91 0.035 95)); +} + +.explorer-search-input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.58rem; + padding: 0.36rem 0.52rem; + background: #fff; +} + +.explorer-search-input:focus { + outline: 2px solid color-mix(in oklab, var(--focus) 48%, transparent); + outline-offset: 1px; +} + +.explorer-toolbar-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.55rem; + color: var(--muted); + font-size: 0.76rem; +} + +.explorer-toolbar-row label { + display: inline-flex; + align-items: center; + gap: 0.28rem; +} + +.explorer-clear-button { + margin-left: auto; + border: 1px solid var(--line); + border-radius: 0.52rem; + background: #fff; + padding: 0.22rem 0.5rem; + cursor: pointer; +} + +.explorer-clear-button:disabled { + opacity: 0.58; + cursor: default; +} + +.explorer-summary { + display: flex; + flex-wrap: wrap; + gap: 0.34rem; + color: var(--muted); + font-size: 0.72rem; +} + +.explorer-summary span { + border: 1px solid color-mix(in oklab, var(--line) 80%, #0000); + border-radius: 999px; + padding: 0.12rem 0.42rem; + background: #fff; +} + +.tree-root { + min-height: 0; + overflow: auto; + border: 1px solid var(--line); + border-radius: 0.7rem; + padding: 0.28rem; + background: color-mix(in oklab, #fff 92%, oklch(0.92 0.03 95)); + scrollbar-width: thin; + display: flex; + flex-direction: column; + gap: 0.14rem; +} + +.tree-node { + display: flex; + gap: 0.24rem; + align-items: stretch; +} + +.tree-node-active .tree-label { + border-color: color-mix(in oklab, var(--focus) 35%, var(--line)); + background: color-mix(in oklab, #fff 80%, oklch(0.88 0.04 219)); +} + +.tree-toggle { + width: 1.42rem; + min-height: 2.15rem; + border-radius: 0.4rem; + border: 1px solid var(--line); + background: #fff; + cursor: pointer; +} + +.tree-toggle-empty { + opacity: 0.55; +} + +.tree-label { + flex: 1; + text-align: left; + display: flex; + flex-direction: column; + align-items: stretch; + gap: 0.15rem; + overflow: hidden; +} + +.tree-label-top { + min-width: 0; + display: inline-flex; + align-items: center; + gap: 0.4rem; +} + +.tree-name { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 600; +} + +.tree-path { + font-family: var(--font-mono); + font-size: 0.67rem; + color: var(--muted); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.kind-pill { + flex: none; + font-size: 0.62rem; + border-radius: 999px; + border: 1px solid color-mix(in oklab, var(--accent) 65%, var(--line)); + background: color-mix(in oklab, var(--accent) 44%, #fff); + padding: 0.1rem 0.4rem; +} + +.tree-duplicate-pill { + flex: none; + font-family: var(--font-mono); + font-size: 0.64rem; + border-radius: 999px; + border: 1px solid color-mix(in oklab, var(--line) 90%, #697177); + background: color-mix(in oklab, #fff 92%, oklch(0.88 0.02 250)); + color: color-mix(in oklab, var(--muted) 76%, var(--ink)); + padding: 0.06rem 0.34rem; +} + +.explorer-empty { + margin: 0.34rem; + border: 1px dashed var(--line); + border-radius: 0.56rem; + padding: 0.72rem; + color: var(--muted); + font-size: 0.8rem; + text-align: center; + background: #fff; +} + +.pane-graph { + min-height: 0; +} + +.graph-header { + display: grid; + grid-template-columns: auto minmax(200px, 360px) minmax(0, 1fr); + align-items: center; + gap: 0.6rem; +} + +.graph-header-title { + display: inline-flex; + align-items: center; + gap: 0.4rem; +} + +.graph-trail-controls { + border-bottom: 1px solid var(--line); + padding: 0.46rem 0.62rem 0.5rem; + display: grid; + gap: 0.38rem; + background: color-mix(in oklab, #fff 90%, oklch(0.9 0.02 95)); +} + +.graph-trail-toolbar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.32rem; +} + +.graph-trail-toolbar button { + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.22rem 0.52rem; + font-size: 0.72rem; + cursor: pointer; +} + +.graph-trail-toolbar button:disabled { + opacity: 0.58; + cursor: default; +} + +.graph-control-field { + min-width: 0; + display: grid; + gap: 0.22rem; + font-size: 0.72rem; + color: var(--muted); +} + +.graph-control-field span { + font-family: var(--font-mono); + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.graph-control-field select, +.graph-control-field input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.5rem; + background: #fff; + min-height: 1.9rem; + padding: 0.26rem 0.44rem; +} + +.trail-dialog-backdrop { + position: fixed; + inset: 0; + background: rgb(17 19 22 / 0.42); + display: grid; + place-items: center; + z-index: 60; +} + +.trail-dialog { + width: min(58rem, calc(100vw - 1.6rem)); + max-height: calc(100vh - 2rem); + border: 1px solid var(--line); + border-radius: 0.86rem; + background: #fff; + box-shadow: 0 22px 42px rgb(12 18 24 / 0.24); + padding: 0.9rem; + overflow: auto; + display: grid; + gap: 0.62rem; +} + +.trail-dialog-header { + display: flex; + align-items: center; + justify-content: space-between; +} + +.trail-dialog-header h3 { + margin: 0; +} + +.trail-dialog-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.52rem; +} + +.trail-dialog-grid-secondary { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.trail-target-field { + position: relative; +} + +.trail-target-placeholder { + display: grid; + gap: 0.22rem; + font-size: 0.72rem; + color: var(--muted); +} + +.trail-target-placeholder span { + font-family: var(--font-mono); + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.trail-target-placeholder-value { + min-height: 1.9rem; + border: 1px solid var(--line); + border-radius: 0.5rem; + background: color-mix(in oklab, #fff 92%, #f3f4f6); + display: flex; + align-items: center; + padding: 0.26rem 0.44rem; +} + +.trail-mode-row { + display: flex; + flex-wrap: wrap; + gap: 0.64rem; + border: 1px solid var(--line); + border-radius: 0.66rem; + padding: 0.5rem; + background: color-mix(in oklab, #fff 92%, oklch(0.9 0.02 95)); +} + +.trail-mode-option { + display: inline-flex; + align-items: center; + gap: 0.32rem; + font-size: 0.78rem; +} + +.trail-range-value { + font-size: 0.7rem; + color: var(--muted); + font-family: var(--font-mono); +} + +.trail-inline-options { + display: flex; + flex-wrap: wrap; + gap: 0.64rem; +} + +.trail-filter-columns { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.62rem; +} + +.trail-filter-column { + border: 1px solid var(--line); + border-radius: 0.66rem; + background: color-mix(in oklab, #fff 95%, oklch(0.9 0.02 95)); + padding: 0.48rem; + display: grid; + gap: 0.42rem; +} + +.trail-filter-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.4rem; +} + +.trail-filter-actions { + display: inline-flex; + gap: 0.25rem; +} + +.trail-filter-actions button { + border: 1px solid var(--line); + border-radius: 999px; + background: #fff; + font-size: 0.64rem; + padding: 0.08rem 0.44rem; + cursor: pointer; +} + +.trail-filter-list { + max-height: 12rem; + overflow: auto; + display: grid; + gap: 0.24rem; + padding-right: 0.22rem; +} + +.trail-filter-item { + display: inline-flex; + align-items: center; + gap: 0.34rem; + font-size: 0.74rem; +} + +.trail-dialog-actions { + display: flex; + justify-content: flex-end; + gap: 0.4rem; +} + +.trail-dialog-actions button { + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.26rem 0.62rem; + cursor: pointer; +} + +.trail-dialog-actions button:disabled { + opacity: 0.58; + cursor: default; +} + +.graph-target-clear { + width: fit-content; + border: 1px solid var(--line); + border-radius: 999px; + background: #fff; + font-size: 0.68rem; + padding: 0.14rem 0.48rem; + cursor: pointer; +} + +.graph-filter-row { + display: grid; + gap: 0.28rem; +} + +.graph-filter-label { + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.02em; + color: var(--muted); + text-transform: uppercase; +} + +.graph-chip-row { + display: flex; + flex-wrap: wrap; + gap: 0.24rem; +} + +.graph-chip-row-grouping { + margin-top: 0.18rem; +} + +.graph-chip { + border: 1px solid var(--line); + border-radius: 999px; + background: #fff; + font-size: 0.67rem; + padding: 0.14rem 0.44rem; + cursor: pointer; +} + +.graph-chip-active { + border-color: color-mix(in oklab, var(--focus) 50%, var(--line)); + background: color-mix(in oklab, #fff 80%, oklch(0.88 0.05 219)); + color: color-mix(in oklab, var(--ink) 85%, #0a2238); +} + +.graph-filter-details { + border: 1px solid color-mix(in oklab, var(--line) 84%, #f0f0f0); + border-radius: 0.5rem; + background: color-mix(in oklab, #fff 92%, oklch(0.92 0.03 95)); + padding: 0.28rem 0.36rem 0.38rem; +} + +.graph-filter-details summary { + cursor: pointer; + font-size: 0.7rem; + color: var(--muted); + margin-bottom: 0.3rem; +} + +.graph-chip-row-node { + margin-top: 0.2rem; +} + +.graph-trail-actions { + display: flex; + align-items: center; + gap: 0.38rem; + flex-wrap: wrap; +} + +.graph-trail-actions button { + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.3rem 0.56rem; + cursor: pointer; +} + +.graph-trail-actions button:disabled { + opacity: 0.58; + cursor: default; +} + +.graph-trail-reason, +.graph-trail-hint { + font-size: 0.72rem; + color: var(--muted); +} + +.graph-trail-reason { + padding-left: 0.1rem; +} + +.graph-trail-hint { + padding-left: 0.1rem; +} + +.trail-target-state { + position: absolute; + right: 0.52rem; + top: 1.9rem; + transform: translateY(-50%); + font-size: 0.66rem; + color: var(--muted); + pointer-events: none; +} + +.truncation-pill { + border: 1px solid color-mix(in oklab, var(--accent) 65%, #5e5d43); + background: color-mix(in oklab, var(--accent) 38%, #fff); + border-radius: 999px; + padding: 0.14rem 0.46rem; + font-size: 0.68rem; + font-weight: 700; +} + +.graph-search-wrap { + position: relative; + min-width: 0; +} + +.graph-search-input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.62rem; + padding: 0.42rem 0.58rem; + background: #fff; +} + +.graph-search-input:focus { + outline: 2px solid color-mix(in oklab, var(--focus) 50%, transparent); + outline-offset: 1px; +} + +.search-state { + position: absolute; + right: 0.52rem; + top: 50%; + transform: translateY(-50%); + font-size: 0.67rem; + color: var(--muted); + pointer-events: none; +} + +.search-dropdown { + position: absolute; + z-index: 30; + top: calc(100% + 0.3rem); + left: 0; + right: 0; + background: #fff; + border: 1px solid var(--line); + border-radius: 0.7rem; + box-shadow: 0 12px 24px rgba(15, 23, 27, 0.16); + max-height: 16rem; + overflow-y: auto; + overflow-x: hidden; + padding: 0.3rem; +} + +.search-hit { + width: 100%; + border: 1px solid transparent; + border-radius: 0.58rem; + background: #fff; + text-align: left; + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.5rem; + padding: 0.34rem 0.5rem; + cursor: pointer; + font-size: 0.78rem; + min-width: 0; +} + +.search-hit-name { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.search-hit-kind { + flex: none; + font-family: var(--font-mono); + font-size: 0.68rem; + color: var(--muted); + letter-spacing: 0.02em; + text-transform: uppercase; +} + +.graph-tabs { + min-width: 0; + flex-wrap: nowrap; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: thin; + padding-bottom: 0.16rem; +} + +.graph-tabs button { + flex: 0 0 auto; + max-width: 18rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.search-hit:hover, +.search-hit-active { + border-color: color-mix(in oklab, var(--focus) 30%, var(--line)); + background: color-mix(in oklab, #fff 80%, oklch(0.88 0.05 95)); +} + +.graph-canvas { + min-height: 0; + flex: 1; + background: + radial-gradient(circle at 7% 12%, rgb(255 255 255 / 0.7), transparent 30%), + radial-gradient(circle at 86% 16%, rgb(255 255 255 / 0.38), transparent 34%), + linear-gradient(180deg, var(--graph-canvas-top), var(--graph-canvas-bottom)); +} + +.graph-flow-shell { + position: relative; + width: 100%; + height: 100%; +} + +.graph-context-menu { + position: absolute; + z-index: 45; + min-width: 12rem; + border: 1px solid var(--graph-chrome-border); + border-radius: 0.66rem; + background: color-mix(in oklab, #fff 90%, var(--graph-chrome-bg)); + box-shadow: 0 14px 24px rgb(14 20 26 / 0.2); + padding: 0.3rem; + display: grid; + gap: 0.2rem; +} + +.graph-context-menu button { + width: 100%; + border: 1px solid transparent; + border-radius: 0.5rem; + background: transparent; + text-align: left; + font-size: 0.74rem; + padding: 0.24rem 0.42rem; + cursor: pointer; + color: var(--ink); +} + +.graph-context-menu button:hover { + border-color: color-mix(in oklab, var(--graph-chrome-border) 72%, #fff); + background: color-mix(in oklab, #fff 68%, var(--graph-chrome-bg)); +} + +.sourcetrail-flow .react-flow__renderer { + background: transparent; +} + +.sourcetrail-flow .react-flow__pane { + cursor: grab; +} + +.sourcetrail-flow .react-flow__pane:active { + cursor: grabbing; +} + +.sourcetrail-flow .react-flow__edge-path { + stroke-linecap: round; + stroke-linejoin: round; +} + +.sourcetrail-flow .react-flow__controls { + border: 1px solid var(--graph-chrome-border); + border-radius: 0.72rem; + box-shadow: 0 8px 18px rgb(15 19 23 / 0.14); + background: var(--graph-chrome-bg); + gap: 0.14rem; + padding: 0.1rem; +} + +.sourcetrail-flow .react-flow__controls button { + border: 1px solid var(--graph-chrome-border); + border-radius: 0.52rem; + background: color-mix(in oklab, #fff 84%, var(--graph-chrome-bg)); + color: #5f6670; + box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.45); +} + +.sourcetrail-flow .react-flow__controls button:hover { + background: color-mix(in oklab, #fff 72%, var(--graph-chrome-bg)); +} + +.sourcetrail-flow .react-flow__minimap, +.graph-minimap { + border: 1px solid var(--graph-chrome-border); + border-radius: 0.72rem; + box-shadow: 0 8px 18px rgb(15 19 23 / 0.14); + background: color-mix(in oklab, #fff 88%, var(--graph-chrome-bg)); +} + +.sourcetrail-flow .react-flow__minimap-mask { + fill: rgb(39 44 52 / 0.16); +} + +.sourcetrail-flow .react-flow__minimap-node { + stroke-width: 0.95; +} + +.graph-zoom-panel { + display: grid; + gap: 0.2rem; + margin-bottom: 0.4rem; +} + +.graph-zoom-panel button, +.graph-legend-toggle-panel button { + min-width: 1.9rem; + min-height: 1.9rem; + border: 1px solid var(--graph-chrome-border); + border-radius: 0.56rem; + background: color-mix(in oklab, #fff 84%, var(--graph-chrome-bg)); + color: #4d545d; + font-family: var(--font-mono); + font-size: 0.78rem; + font-weight: 700; + box-shadow: + inset 0 1px 0 rgb(255 255 255 / 0.45), + 0 6px 14px rgb(15 19 23 / 0.12); + cursor: pointer; +} + +.graph-zoom-panel button:hover, +.graph-legend-toggle-panel button:hover { + background: color-mix(in oklab, #fff 72%, var(--graph-chrome-bg)); +} + +.graph-legend-toggle-panel { + margin-bottom: 0.2rem; +} + +.graph-legend-panel { + min-width: 10rem; + border: 1px solid var(--graph-chrome-border); + border-radius: 0.74rem; + background: color-mix(in oklab, #fff 84%, var(--graph-chrome-bg)); + box-shadow: 0 10px 22px rgb(14 20 26 / 0.16); + padding: 0.45rem 0.5rem; + margin-bottom: 2.4rem; +} + +.graph-legend-title { + font-family: var(--font-mono); + font-size: 0.68rem; + text-transform: uppercase; + letter-spacing: 0.02em; + color: var(--muted); + margin-bottom: 0.3rem; +} + +.graph-legend-rows { + display: grid; + gap: 0.18rem; +} + +.graph-legend-row { + width: 100%; + border: 1px solid transparent; + border-radius: 0.5rem; + background: transparent; + padding: 0.18rem 0.2rem; + display: grid; + grid-template-columns: 1.2rem 1fr auto; + align-items: center; + gap: 0.3rem; + text-align: left; + cursor: pointer; +} + +.graph-legend-row:hover { + border-color: color-mix(in oklab, var(--graph-chrome-border) 72%, #fff); + background: color-mix(in oklab, #fff 62%, var(--graph-chrome-bg)); +} + +.graph-legend-row-muted { + opacity: 0.45; +} + +.graph-legend-row-active { + opacity: 1; +} + +.graph-legend-line { + display: inline-block; + height: 0.2rem; + border-radius: 999px; +} + +.graph-legend-kind { + font-size: 0.7rem; + color: var(--ink); +} + +.graph-legend-count { + font-family: var(--font-mono); + font-size: 0.66rem; + color: var(--muted); +} + +.graph-legend-note { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.35rem; + margin-top: 0.42rem; + font-size: 0.64rem; + color: var(--muted); + line-height: 1.35; +} + +.graph-legend-reset { + border: 1px solid var(--graph-chrome-border); + border-radius: 999px; + background: #fff; + color: #4f5660; + font-family: var(--font-mono); + font-size: 0.62rem; + padding: 0.08rem 0.44rem; + cursor: pointer; +} + +.graph-node { + position: relative; + min-width: 210px; + border-radius: 18px; + border: 1px solid var(--graph-node-shell-border); + background: var(--graph-node-shell); + padding: 0.58rem 0.6rem 0.64rem; + box-shadow: 0 4px 12px rgb(0 0 0 / 0.05); + color: #1c1f23; + transition: box-shadow 180ms ease; +} + +.graph-node-file { + border-color: color-mix(in oklab, var(--graph-file-accent) 52%, var(--graph-node-shell-border)); + box-shadow: + inset 0 1px 0 rgb(255 255 255 / 0.45), + 0 0 0 2px color-mix(in oklab, var(--graph-file-accent) 35%, transparent); +} + +.graph-node-file-tab { + position: absolute; + left: -0.5rem; + top: -1.66rem; + border: 1px solid + color-mix(in oklab, var(--graph-file-accent) 56%, var(--graph-node-shell-border)); + border-bottom: none; + border-radius: 0.8rem 0.8rem 0 0; + background: color-mix(in oklab, var(--graph-file-accent) 76%, #fff); + padding: 0.22rem 0.88rem 0.26rem; + font-family: var(--font-mono); + font-size: 0.76rem; + letter-spacing: 0.01em; + font-weight: 700; + color: color-mix(in oklab, #354046 72%, #000); +} + +.graph-node-title-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + margin-bottom: 0.42rem; +} + +.graph-node-title { + font-family: var(--font-mono); + font-size: 0.86rem; + letter-spacing: 0.01em; +} + +.graph-node-count { + min-width: 1.9rem; + border-radius: 999px; + border: 1px solid color-mix(in oklab, var(--graph-node-core-border) 70%, #9da3ab); + background: color-mix(in oklab, var(--graph-node-core) 74%, #ebedf0); + padding: 0.12rem 0.46rem; + text-align: center; + font-family: var(--font-mono); + font-size: 0.7rem; + font-weight: 700; + color: #1d2125; +} + +.graph-node-toggle { + display: inline-flex; + align-items: center; + gap: 0.28rem; + border: none; + background: transparent; + padding: 0; + cursor: pointer; +} + +.graph-node-toggle:disabled { + cursor: default; +} + +.graph-node-chevron { + font-family: var(--font-mono); + font-size: 0.68rem; + color: #4d545c; + line-height: 1; +} + +.graph-node-body { + border-radius: 14px; + border: 1px solid var(--graph-node-core-border); + background: var(--graph-node-core); + min-height: 2.7rem; + padding: 0.52rem; + display: flex; + flex-direction: column; + gap: 0.4rem; +} + +.graph-node-section { + width: 100%; + border-radius: 0.68rem; + border: 1px solid color-mix(in oklab, var(--graph-node-core-border) 88%, #efefef); + background: color-mix(in oklab, #fff 94%, var(--graph-node-core)); + padding: 0.38rem 0.38rem 0.35rem; +} + +.graph-node-section-empty { + border-style: dashed; +} + +.graph-node-section-header { + width: 100%; + display: flex; + align-items: center; + gap: 0.34rem; + margin-bottom: 0.36rem; + padding-bottom: 0.2rem; + border-bottom: 1px dashed color-mix(in oklab, var(--graph-node-core-border) 74%, #d8dadd); + letter-spacing: 0.01em; + font-family: var(--font-mono); + font-size: 0.71rem; + font-weight: 700; + color: #2f353b; + text-transform: uppercase; +} + +.graph-node-section-title { + line-height: 1; +} + +.graph-node-section-count { + margin-left: auto; + border-radius: 999px; + border: 1px solid color-mix(in oklab, var(--graph-node-core-border) 84%, #969ca4); + background: color-mix(in oklab, #fff 78%, var(--graph-node-core)); + padding: 0.04rem 0.34rem; + font-size: 0.62rem; + color: #596069; + line-height: 1.2; +} + +.graph-node-section-count-public { + border-color: color-mix(in oklab, var(--graph-public-chip-border) 82%, #8c8d7e); + background: color-mix(in oklab, var(--graph-public-chip) 24%, #fff); +} + +.graph-node-section-count-private { + border-color: color-mix(in oklab, var(--graph-private-chip-border) 82%, #7e8796); + background: color-mix(in oklab, var(--graph-private-chip) 24%, #fff); +} + +.graph-section-dot { + display: flex; + align-items: center; + justify-content: center; + font-size: 0.8rem; + line-height: 1; + color: #6a727a; +} + +.graph-node-members { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 0.34rem; +} + +.graph-member-chip { + position: relative; + display: flex; + align-items: center; + min-height: 1.44rem; + border-radius: 999px; + border: 1px solid var(--graph-public-chip-border); + background: var(--graph-public-chip); + padding: 0.18rem 0.58rem; + max-width: 100%; + transition: + border-color 160ms ease, + box-shadow 160ms ease, + background 160ms ease; +} + +.graph-member-chip-button { + width: 100%; + appearance: none; + text-align: left; + cursor: pointer; +} + +.graph-member-chip-public { + border-color: #f7dca1; + background: #fdf2d0; +} + +.graph-member-chip-private { + border-color: #b3d1e6; + background: #e6f3fc; +} + +.graph-member-chip-focused { + border-color: color-mix(in oklab, var(--focus) 60%, #516270); + background: color-mix(in oklab, #fff 66%, var(--focus)); + box-shadow: + 0 0 0 1px color-mix(in oklab, var(--focus) 46%, transparent), + inset 0 1px 0 rgb(255 255 255 / 0.54); +} + +.graph-node-center .graph-member-chip-focused { + border-color: color-mix(in oklab, var(--focus) 72%, #2f3a48); + box-shadow: + 0 0 0 2px color-mix(in oklab, var(--focus) 38%, transparent), + inset 0 1px 0 rgb(255 255 255 / 0.64); +} + +.graph-node-center .graph-member-chip-focused .graph-member-name { + font-weight: 700; +} + +.graph-member-name { + font-family: var(--font-mono); + font-size: 0.72rem; + color: #15181c; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.graph-member-more { + font-family: var(--font-mono); + font-size: 0.66rem; + color: #6a727a; + padding-left: 0.22rem; +} + +.graph-node-center { + border: 2px solid #555; +} + +.graph-node-selected { + box-shadow: + 0 0 0 2px rgb(47 58 65 / 0.28), + inset 0 1px 0 rgb(255 255 255 / 0.42); +} + +.graph-floating-pill { + position: relative; + display: inline-flex; + align-items: center; + gap: 0.3rem; + min-width: 3.7rem; + width: fit-content; + max-width: none; + border-radius: 999px; + border: 1px solid #c2c9d1; + background: #ebedf0; + padding: 0.34rem 0.76rem; + font-family: var(--font-mono); + font-size: 0.74rem; + color: #101215; + line-height: 1.1; + white-space: nowrap; +} + +.graph-pill-duplicate-count { + margin-left: 0.38rem; + border-radius: 999px; + border: 1px solid color-mix(in oklab, var(--graph-public-chip-border) 70%, #9f8b57); + background: color-mix(in oklab, var(--graph-public-chip) 62%, #fff); + padding: 0.08rem 0.34rem; + font-size: 0.64rem; + font-weight: 700; +} + +.graph-floating-pill-center { + border-color: #31353c; + box-shadow: 0 0 0 2px rgba(49, 53, 60, 0.45); +} + +.graph-floating-pill-selected { + box-shadow: 0 0 0 2px rgba(49, 53, 60, 0.35); +} + +.graph-floating-pill-simple { + border-style: solid; + border-color: #d1d6dc; + background: repeating-linear-gradient(-45deg, #f5f7f9 0 8px, #e2e6eb 8px 16px); + color: #2f353b; + box-shadow: none; +} + +.graph-node-unresolved { + background-image: repeating-linear-gradient( + -45deg, + rgb(227 232 238 / 0.82) 0 9px, + rgb(245 247 250 / 0.95) 9px 18px + ); +} + +.graph-bundle-node { + width: 6px; + height: 6px; + border-radius: 999px; + background: transparent; + border: none; + box-shadow: none; + opacity: 0; + pointer-events: none; +} + +.react-flow__node-sourcetrailGroup { + background: transparent !important; + border: none !important; + box-shadow: none !important; + padding: 0 !important; +} + +.graph-group-node { + width: 100%; + height: 100%; + border: 2px solid #d7dade; + border-radius: 1rem; + background: color-mix(in oklab, #fff 64%, var(--graph-node-shell)); + pointer-events: none; + position: relative; +} + +.graph-group-node-file { + border-color: #aacd95; + background: color-mix(in oklab, #f4fbef 88%, #fff); +} + +.graph-group-node-namespace { + border-color: #e2bcc1; + background: color-mix(in oklab, #fdf4f5 88%, #fff); +} + +.graph-group-label { + position: absolute; + top: 0.52rem; + left: 0.78rem; + border-radius: 0.65rem 0.65rem 0.85rem 0.85rem; + border: 1px solid color-mix(in oklab, #c9ced5 72%, #fff); + background: color-mix(in oklab, #f0f2f5 88%, #fff); + padding: 0.12rem 0.55rem; + font-family: var(--font-mono); + font-size: 0.72rem; + font-weight: 700; + color: #4d5966; +} + +.graph-group-node-file .graph-group-label { + border-color: #98bf84; + background: #d8ebc9; + color: #455b49; +} + +.graph-group-node-namespace .graph-group-label { + border-color: #deafb5; + background: #f0d0d3; + color: #6c4b54; +} + +/* Strip the React Flow wrapper node of all visual styling for bundle nodes */ +.react-flow__node:has(.graph-bundle-node) { + background: transparent !important; + border: none !important; + box-shadow: none !important; + padding: 0 !important; + min-width: 0 !important; + min-height: 0 !important; + width: 6px !important; + height: 6px !important; + pointer-events: none !important; + opacity: 0 !important; +} + +.graph-edge-tooltip { + position: absolute; + pointer-events: none; + border: 1px solid color-mix(in oklab, var(--graph-chrome-border) 88%, #fff); + border-radius: 0.42rem; + background: color-mix(in oklab, #fff 90%, var(--graph-chrome-bg)); + color: #3d4650; + font-family: var(--font-mono); + font-size: 0.61rem; + font-weight: 700; + letter-spacing: 0.01em; + text-transform: lowercase; + white-space: nowrap; + padding: 0.08rem 0.42rem; + box-shadow: 0 6px 12px rgb(20 24 28 / 0.16); +} + +.graph-handle { + width: 6px; + height: 6px; + opacity: 0; + border: none; + background: transparent; +} + +.graph-bundle-handle { + pointer-events: none; +} + +.graph-member-handle { + top: 50%; +} + +.graph-handle-target { + left: -6px; +} + +.graph-member-handle-target { + left: -5px; +} + +.graph-handle-source { + right: -6px; +} + +.graph-handle-top { + top: -6px; +} + +.graph-handle-bottom { + bottom: -6px; +} + +.graph-member-handle-source { + right: -5px; +} + +.graph-hidden-member-handles { + position: absolute; + inset: 0; + pointer-events: none; +} + +.graph-hidden-member-handle-pair { + position: relative; + width: 100%; + height: 0; +} + +.graph-hidden-member-handle { + opacity: 0; + pointer-events: none; +} + +.graph-empty { + margin: 0.7rem; + border: 1px dashed var(--line); + border-radius: 0.86rem; + padding: 1rem; + background: color-mix(in oklab, #fff 64%, oklch(0.89 0.043 95)); + color: var(--muted); +} + +.graph-empty strong { + display: block; + margin-bottom: 0.35rem; + color: color-mix(in oklab, var(--ink) 90%, #0d2438); +} + +.graph-empty p { + margin: 0; +} + +.mermaid-shell { + height: 100%; + overflow: auto; + padding: 1rem; + background: color-mix(in oklab, #fff 88%, #e8eaeb); +} + +.pane-code { + min-height: 0; +} + +.code-occurrence-toolbar { + margin: 0 0.7rem; + border: 1px solid var(--line); + border-radius: 0.74rem; + background: color-mix(in oklab, #fff 90%, oklch(0.9 0.03 95)); + padding: 0.35rem 0.48rem; + display: grid; + grid-template-columns: auto auto auto minmax(0, 1fr); + align-items: center; + gap: 0.38rem; +} + +.code-occurrence-toolbar button { + border: 1px solid var(--line); + border-radius: 0.5rem; + background: #fff; + padding: 0.2rem 0.5rem; + cursor: pointer; +} + +.code-occurrence-toolbar button:disabled { + opacity: 0.58; + cursor: default; +} + +.code-occurrence-summary { + font-family: var(--font-mono); + font-size: 0.68rem; + color: var(--muted); +} + +.code-occurrence-list { + min-width: 0; + display: flex; + gap: 0.22rem; + overflow-x: auto; + overflow-y: hidden; + padding-bottom: 0.08rem; + scrollbar-width: thin; +} + +.code-occurrence-chip { + flex: 0 0 auto; + font-family: var(--font-mono); + font-size: 0.64rem; + border: 1px solid var(--line); + border-radius: 999px; + background: #fff; + padding: 0.1rem 0.44rem; + cursor: pointer; +} + +.code-occurrence-chip.active { + border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); + background: color-mix(in oklab, #fff 78%, oklch(0.88 0.05 219)); +} + +.pane-code-header button { + border: 1px solid var(--line); + border-radius: 0.62rem; + background: #fff; + padding: 0.35rem 0.64rem; + font-weight: 600; + cursor: pointer; +} + +.pane-code-header button:disabled { + opacity: 0.6; + cursor: default; +} + +.node-meta { + margin: 0.7rem; + border: 1px solid var(--line); + border-radius: 0.78rem; + background: #fff; + padding: 0.56rem 0.64rem; + display: grid; + gap: 0.24rem; +} + +.node-meta strong { + margin-right: 0.5rem; +} + +.dirty-pill { + margin-left: 0.45rem; + border: 1px solid color-mix(in oklab, var(--accent) 65%, #5e5d43); + background: color-mix(in oklab, var(--accent) 35%, #fff); + border-radius: 999px; + padding: 0.08rem 0.42rem; + font-size: 0.66rem; + font-weight: 700; +} + +.monaco-shell { + margin: 0 0.7rem 0.7rem; + border: 1px solid var(--line); + border-radius: 0.78rem; + overflow: hidden; + min-height: 16rem; + flex: 1; +} + +.monaco-focus-line { + background: color-mix(in oklab, #f0b429 28%, transparent) !important; +} + +.monaco-focus-range { + background: color-mix(in oklab, #f0b429 26%, transparent) !important; + border-bottom: 1px solid color-mix(in oklab, #f0b429 65%, #8d7d3f); +} + +.monaco-focus-inline { + background: color-mix(in oklab, #f0b429 28%, transparent) !important; +} + +.confirm-overlay { + position: fixed; + inset: 0; + background: rgba(17, 19, 22, 0.42); + display: grid; + place-items: center; + z-index: 50; +} + +.confirm-modal { + width: min(27rem, calc(100vw - 2rem)); + border: 1px solid var(--line); + border-radius: 0.86rem; + background: #fff; + box-shadow: 0 22px 42px rgba(12, 18, 24, 0.24); + padding: 1rem; +} + +.confirm-modal h3 { + margin: 0 0 0.4rem; +} + +.confirm-modal p { + margin: 0; + color: var(--muted); +} + +.confirm-actions { + margin-top: 0.9rem; + display: flex; + justify-content: flex-end; + gap: 0.5rem; +} + +.confirm-actions button { + border: 1px solid var(--line); + border-radius: 0.62rem; + background: #fff; + padding: 0.35rem 0.7rem; + cursor: pointer; +} + +.confirm-actions .confirm-primary { + border-color: color-mix(in oklab, var(--accent) 65%, #5e5d43); + background: color-mix(in oklab, var(--accent) 45%, #fff); + font-weight: 700; +} + +.command-palette-overlay { + position: fixed; + inset: 0; + background: rgb(17 19 22 / 0.38); + display: grid; + place-items: start center; + padding-top: min(18vh, 8rem); + z-index: 72; +} + +.command-palette { + width: min(36rem, calc(100vw - 1.6rem)); + border: 1px solid var(--line); + border-radius: 0.86rem; + background: color-mix(in oklab, #fff 94%, var(--surface-1)); + box-shadow: 0 18px 36px rgb(12 18 24 / 0.24); + padding: 0.72rem; + display: grid; + gap: 0.54rem; +} + +.command-palette label { + font-family: var(--font-mono); + font-size: 0.68rem; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.command-palette input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.68rem; + background: #fff; + padding: 0.5rem 0.62rem; +} + +.command-palette input:focus { + outline: 2px solid color-mix(in oklab, var(--focus) 48%, transparent); + outline-offset: 1px; +} + +.command-palette-results { + max-height: min(50vh, 22rem); + overflow: auto; + display: grid; + gap: 0.32rem; + padding-right: 0.14rem; +} + +.command-palette-item { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.62rem; + background: #fff; + text-align: left; + padding: 0.42rem 0.56rem; + cursor: pointer; + display: grid; + gap: 0.08rem; +} + +.command-palette-item span { + font-size: 0.86rem; + font-weight: 700; +} + +.command-palette-item small { + font-size: 0.72rem; + color: var(--muted); +} + +.command-palette-item-active { + border-color: color-mix(in oklab, var(--focus) 50%, var(--line)); + background: color-mix(in oklab, #fff 76%, oklch(0.88 0.05 219)); +} + +.command-palette-item:disabled { + opacity: 0.55; + cursor: default; +} + +.command-palette-empty { + margin: 0; + border: 1px dashed var(--line); + border-radius: 0.62rem; + background: #fff; + color: var(--muted); + padding: 0.58rem; + text-align: center; +} + +.workspace-learn { + grid-template-columns: minmax(340px, 1.15fr) minmax(360px, 1.05fr) minmax(340px, 1fr); +} + +.workspace-debug { + grid-template-columns: minmax(260px, 0.9fr) minmax(560px, 1.6fr) minmax(320px, 1fr); +} + +.workspace-review { + grid-template-columns: minmax(320px, 1fr) minmax(360px, 1fr) minmax(440px, 1.4fr); +} + +.advanced-settings { + margin: 0.68rem; + border-top: 1px solid var(--line); + padding-top: 0.54rem; +} + +.advanced-settings-toggle { + border: 1px solid var(--line); + border-radius: 0.6rem; + background: #fff; + padding: 0.3rem 0.6rem; + font-size: 0.74rem; + cursor: pointer; +} + +.advanced-settings-drawer { + margin-top: 0.56rem; + border: 1px solid var(--line); + border-radius: 0.72rem; + background: color-mix(in oklab, #fff 92%, oklch(0.9 0.03 95)); + overflow: hidden; +} + +.response-answer-cards { + display: grid; + gap: 0.62rem; + padding-bottom: 0.7rem; +} + +.section-card-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.55rem; + flex-wrap: wrap; +} + +.section-card-header h3, +.section-card-header h4 { + margin: 0; +} + +.section-card-actions { + display: inline-flex; + flex-wrap: wrap; + gap: 0.34rem; +} + +.section-card-actions button { + border: 1px solid var(--line); + border-radius: 0.55rem; + background: #fff; + padding: 0.26rem 0.55rem; + cursor: pointer; +} + +.response-citation-list { + margin: 0; + padding: 0; + list-style: none; + display: grid; + gap: 0.46rem; +} + +.response-citation-item { + border: 1px solid var(--line); + border-radius: 0.62rem; + background: color-mix(in oklab, #fff 90%, oklch(0.91 0.03 95)); + padding: 0.46rem; + display: grid; + gap: 0.34rem; +} + +.response-citation-item button { + border: 1px solid var(--line); + border-radius: 0.5rem; + background: #fff; + padding: 0.24rem 0.52rem; + cursor: pointer; + justify-self: start; +} + +.response-citation-meta { + display: flex; + flex-wrap: wrap; + gap: 0.38rem; + align-items: center; +} + +.shell-section-grid { + width: 100%; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 0.7rem; + align-content: start; +} + +.shell-card { + border: 1px solid var(--line); + border-radius: 0.9rem; + background: color-mix(in oklab, #fff 92%, var(--surface-1)); + box-shadow: 0 10px 20px rgb(17 24 31 / 0.07); + padding: 0.8rem; + display: grid; + gap: 0.48rem; + min-height: 0; +} + +.shell-card h3, +.shell-card h4 { + margin: 0; +} + +.shell-card p { + margin: 0; + color: var(--muted); +} + +.shell-card input, +.shell-card select, +.shell-card textarea, +.shell-card button { + font: inherit; +} + +.shell-card input, +.shell-card select, +.shell-card textarea { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.34rem 0.48rem; +} + +.shell-card button { + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.28rem 0.58rem; + cursor: pointer; +} + +.shell-card ul, +.shell-card ol { + margin: 0; + padding-left: 1.15rem; + display: grid; + gap: 0.34rem; +} + +.shell-card li { + color: color-mix(in oklab, var(--ink) 90%, #111); +} + +.shell-inline-actions { + display: flex; + flex-wrap: wrap; + gap: 0.42rem; +} + +.shell-toggle { + display: inline-flex; + align-items: center; + gap: 0.42rem; +} + +.settings-page { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.9rem; + background: color-mix(in oklab, #fff 92%, var(--surface-1)); + box-shadow: 0 10px 20px rgb(17 24 31 / 0.07); + padding: 0.82rem; + display: grid; + gap: 0.62rem; +} + +.settings-page-header h3 { + margin: 0; +} + +.settings-page-header p { + margin: 0.2rem 0 0; + color: var(--muted); +} + +.settings-groups { + display: grid; + gap: 0.45rem; +} + +.settings-toggle { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.settings-help-card { + border: 1px dashed var(--line); + border-radius: 0.7rem; + padding: 0.55rem; + background: #fff; + display: grid; + gap: 0.18rem; +} + +.settings-help-card h4, +.settings-help-card p { + margin: 0; +} + +.settings-help-card p { + color: var(--muted); +} + +.spaces-panel { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.9rem; + background: color-mix(in oklab, #fff 92%, var(--surface-1)); + box-shadow: 0 10px 20px rgb(17 24 31 / 0.07); + padding: 0.85rem; + display: grid; + gap: 0.62rem; + min-height: 0; +} + +.spaces-panel-header h3 { + margin: 0; +} + +.spaces-panel-header p { + margin: 0.2rem 0 0; + color: var(--muted); +} + +.spaces-create, +.spaces-filter-row { + display: grid; + gap: 0.42rem; +} + +.spaces-create input, +.spaces-create textarea, +.spaces-filter-row input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.34rem 0.48rem; +} + +.spaces-create button { + width: fit-content; + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.28rem 0.58rem; + cursor: pointer; +} + +.spaces-list { + min-height: 0; + overflow: auto; + display: grid; + gap: 0.46rem; +} + +.spaces-item { + border: 1px solid var(--line); + border-radius: 0.66rem; + background: #fff; + padding: 0.5rem; + display: grid; + gap: 0.34rem; +} + +.spaces-item-active { + border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); + background: color-mix(in oklab, #fff 78%, oklch(0.88 0.05 219)); +} + +.spaces-item h4 { + margin: 0; +} + +.spaces-item p { + margin: 0; + color: var(--muted); +} + +.spaces-item-notes { + font-family: var(--font-mono); + font-size: 0.72rem; +} + +.spaces-item-meta { + display: inline-flex; + gap: 0.5rem; + flex-wrap: wrap; + font-size: 0.72rem; + color: var(--muted); +} + +.spaces-item-actions { + display: inline-flex; + gap: 0.36rem; +} + +.spaces-item-actions button { + border: 1px solid var(--line); + border-radius: 0.5rem; + background: #fff; + padding: 0.22rem 0.48rem; + cursor: pointer; +} + +.spaces-empty { + border: 1px dashed var(--line); + border-radius: 0.6rem; + padding: 0.6rem; + text-align: center; + color: var(--muted); +} + +.bookmark-manager-overlay { + position: fixed; + inset: 0; + background: rgb(17 19 22 / 0.42); + display: grid; + place-items: center; + z-index: 65; +} + +.bookmark-manager { + width: min(70rem, calc(100vw - 1.6rem)); + max-height: calc(100vh - 1.6rem); + border: 1px solid var(--line); + border-radius: 0.86rem; + background: #fff; + box-shadow: 0 22px 42px rgb(12 18 24 / 0.24); + padding: 0.9rem; + display: grid; + gap: 0.62rem; + overflow: auto; +} + +.bookmark-manager-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.5rem; +} + +.bookmark-manager-header h3 { + margin: 0; +} + +.bookmark-manager-header button { + border: 1px solid var(--line); + border-radius: 0.56rem; + background: #fff; + padding: 0.22rem 0.58rem; + cursor: pointer; +} + +.bookmark-manager-columns { + display: grid; + grid-template-columns: minmax(240px, 1fr) minmax(380px, 1.4fr); + gap: 0.62rem; + min-height: 0; +} + +.bookmark-section { + border: 1px solid var(--line); + border-radius: 0.72rem; + background: color-mix(in oklab, #fff 94%, oklch(0.9 0.02 95)); + padding: 0.56rem; + display: grid; + gap: 0.46rem; + min-height: 0; +} + +.bookmark-section h4 { + margin: 0; + font-size: 0.84rem; +} + +.bookmark-inline-row { + display: flex; + gap: 0.3rem; + align-items: center; +} + +.bookmark-inline-row input, +.bookmark-inline-row select, +.bookmark-seed-card textarea, +.bookmark-item textarea, +.bookmark-category-row input { + width: 100%; + border: 1px solid var(--line); + border-radius: 0.5rem; + background: #fff; + min-height: 1.85rem; + padding: 0.22rem 0.44rem; +} + +.bookmark-inline-row button, +.bookmark-item button, +.bookmark-category-row button, +.bookmark-seed-card button { + border: 1px solid var(--line); + border-radius: 0.48rem; + background: #fff; + padding: 0.18rem 0.52rem; + cursor: pointer; + font-size: 0.72rem; +} + +.bookmark-category-filter { + display: flex; + flex-wrap: wrap; + gap: 0.26rem; +} + +.bookmark-category-filter button { + border: 1px solid var(--line); + border-radius: 999px; + background: #fff; + padding: 0.12rem 0.5rem; + font-size: 0.68rem; + cursor: pointer; +} + +.bookmark-category-filter .bookmark-active { + border-color: color-mix(in oklab, var(--focus) 45%, var(--line)); + background: color-mix(in oklab, #fff 80%, oklch(0.88 0.05 219)); +} + +.bookmark-list { + display: grid; + gap: 0.34rem; + overflow: auto; + min-height: 0; +} + +.bookmark-category-row { + display: grid; + grid-template-columns: minmax(0, 1fr) auto auto; + gap: 0.24rem; +} + +.bookmark-seed-card { + border: 1px solid var(--line); + border-radius: 0.62rem; + background: #fff; + padding: 0.5rem; + display: grid; + gap: 0.34rem; +} + +.bookmark-seed-title { + font-size: 0.72rem; + text-transform: uppercase; + color: var(--muted); + font-family: var(--font-mono); +} + +.bookmark-seed-label { + font-weight: 700; + font-size: 0.84rem; +} + +.bookmark-item { + border: 1px solid var(--line); + border-radius: 0.62rem; + background: #fff; + padding: 0.46rem; + display: grid; + gap: 0.3rem; +} + +.bookmark-node-link { + border: none; + background: transparent; + text-align: left; + padding: 0; + color: color-mix(in oklab, var(--ink) 90%, #08203b); + font-weight: 700; + cursor: pointer; +} + +.bookmark-node-link:hover { + text-decoration: underline; +} + +.bookmark-empty { + border: 1px dashed var(--line); + border-radius: 0.56rem; + background: #fff; + color: var(--muted); + padding: 0.7rem; + text-align: center; + font-size: 0.76rem; +} + +@media (max-width: 700px) { + .app-body { + grid-template-columns: 1fr; + padding: var(--space-2); + } + + .app-nav { + padding: var(--space-3); + } + + .app-nav-links { + grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); + } + + .topbar { + padding: 0.8rem var(--space-3); + } + + .status-strip { + padding: 0.45rem var(--space-3); + } + + .investigate-toolbar { + align-items: stretch; + } + + .investigate-toolbar-actions { + width: 100%; + justify-content: flex-start; + } + + .focus-switcher { + width: 100%; + justify-content: space-between; + } + + .agent-connection-settings { + grid-template-columns: 1fr; + } + + .explorer-toolbar-row { + font-size: 0.72rem; + } + + .explorer-clear-button { + margin-left: 0; + } +} + +@media (max-width: 1200px) { + .app-body { + grid-template-columns: 1fr; + } + + .app-nav-links { + grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); + } + + .workspace { + grid-template-columns: 1fr; + grid-template-rows: minmax(320px, auto) minmax(420px, 1fr) minmax(360px, auto); + } + + .investigate-pane { + min-height: 60vh; + max-height: none; + } + + .path-input { + min-width: 11rem; + } + + .graph-header { + grid-template-columns: 1fr; + align-items: stretch; + } + + .graph-trail-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .trail-dialog-grid, + .trail-dialog-grid-secondary, + .trail-filter-columns { + grid-template-columns: 1fr; + } + + .bookmark-manager-columns { + grid-template-columns: 1fr; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 1ms !important; + animation-iteration-count: 1 !important; + transition-duration: 1ms !important; + scroll-behavior: auto !important; + } +} diff --git a/codestory-ui/src/theme/tokens.css b/codestory-ui/src/theme/tokens.css new file mode 100644 index 0000000..a95759e --- /dev/null +++ b/codestory-ui/src/theme/tokens.css @@ -0,0 +1,66 @@ +:root { + --font-heading: "Outfit", system-ui, sans-serif; + --font-body: "Plus Jakarta Sans", system-ui, sans-serif; + --font-mono: "JetBrains Mono", "Consolas", monospace; + + --color-background: #fffdf5; + --color-foreground: #1e293b; + --color-muted: #f1f5f9; + --color-muted-foreground: #64748b; + --color-accent: #8b5cf6; + --color-accent-foreground: #ffffff; + --color-secondary: #f472b6; + --color-tertiary: #fbbf24; + --color-quaternary: #34d399; + --color-border: #e2e8f0; + --color-card: #ffffff; + --color-input: #ffffff; + --color-ring: #8b5cf6; + --color-shadow: #1e293b; + + --radius-sm: 8px; + --radius-md: 16px; + --radius-lg: 24px; + --radius-full: 9999px; + --border-width: 2px; + + --shadow-pop: 4px 4px 0 0 var(--color-shadow); + --shadow-pop-hover: 6px 6px 0 0 var(--color-shadow); + --shadow-pop-active: 2px 2px 0 0 var(--color-shadow); + + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.25rem; + + --duration-fast: 140ms; + --duration-medium: 220ms; + --duration-playful: 300ms; + --ease-playful: cubic-bezier(0.34, 1.56, 0.64, 1); + + --graph-canvas-top: #fffdf5; + --graph-canvas-bottom: #fff6d8; + --graph-chrome-bg: #fffdf5e6; + --graph-chrome-border: #d5def3; + --graph-node-shell: #ffffff; + --graph-node-shell-border: #c9d5f3; + --graph-node-core: #ffffff; + --graph-node-core-border: #bfd0f2; + --graph-file-accent: #34d399; + --graph-public-chip: #dcfce7; + --graph-public-chip-border: #22c55e; + --graph-private-chip: #fbcfe8; + --graph-private-chip-border: #ec4899; + + --surface-1: color-mix(in oklab, var(--color-card) 90%, var(--color-background)); + --surface-2: color-mix(in oklab, var(--color-muted) 70%, var(--color-background)); + + --bg: var(--color-background); + --bg-elevated: color-mix(in oklab, var(--color-background) 72%, white); + --ink: var(--color-foreground); + --muted: var(--color-muted-foreground); + --line: var(--color-border); + --accent: var(--color-accent); + --focus: var(--color-ring); + --font-ui: var(--font-body); +} diff --git a/codestory-ui/src/theme/tokens.ts b/codestory-ui/src/theme/tokens.ts new file mode 100644 index 0000000..d50cfe3 --- /dev/null +++ b/codestory-ui/src/theme/tokens.ts @@ -0,0 +1,70 @@ +export const PLAYFUL_TOKENS = { + colors: { + background: "#FFFDF5", + foreground: "#1E293B", + muted: "#F1F5F9", + mutedForeground: "#64748B", + accent: "#8B5CF6", + accentForeground: "#FFFFFF", + secondary: "#F472B6", + tertiary: "#FBBF24", + quaternary: "#34D399", + border: "#E2E8F0", + input: "#FFFFFF", + card: "#FFFFFF", + ring: "#8B5CF6", + shadow: "#1E293B", + }, + radius: { + sm: "8px", + md: "16px", + lg: "24px", + full: "9999px", + }, + spacing: { + 2: "0.5rem", + 3: "0.75rem", + 4: "1rem", + 5: "1.25rem", + }, + motion: { + fast: "140ms", + medium: "220ms", + playful: "300ms", + bounce: "cubic-bezier(0.34, 1.56, 0.64, 1)", + }, +} as const; + +export const EDGE_KIND_COLORS = { + MEMBER: "#94A3B8", + TYPE_USAGE: "#0EA5E9", + USAGE: "#8B5CF6", + CALL: "#F59E0B", + INHERITANCE: "#475569", + OVERRIDE: "#EC4899", + TYPE_ARGUMENT: "#22C55E", + TEMPLATE_SPECIALIZATION: "#14B8A6", + INCLUDE: "#FB7185", + IMPORT: "#F97316", + MACRO_USAGE: "#A78BFA", + ANNOTATION_USAGE: "#06B6D4", + UNKNOWN: "#64748B", +} as const; + +export const GRAPH_THEME = { + minimap: { + nodeDefault: "#C4B5FD", + nodeCenter: "#8B5CF6", + nodeFile: "#34D399", + nodeGroupFile: "#FBBF24", + nodeGroupNamespace: "#F472B6", + nodeVirtualBundle: "#94A3B8", + strokeDefault: "#334155", + strokeGroupFile: "#CA8A04", + strokeGroupNamespace: "#DB2777", + background: "rgb(255 253 245 / 0.94)", + mask: "rgb(30 41 59 / 0.15)", + }, + exportBackground: "#FFFDF5", + editorOverview: "#8B5CF688", +} as const; diff --git a/codestory-ui/src/ui/primitives/Badge.tsx b/codestory-ui/src/ui/primitives/Badge.tsx new file mode 100644 index 0000000..c2f8b5d --- /dev/null +++ b/codestory-ui/src/ui/primitives/Badge.tsx @@ -0,0 +1,25 @@ +import type { HTMLAttributes } from "react"; + +import { cx } from "./cx"; + +type BadgeTone = "default" | "accent" | "secondary" | "tertiary" | "quaternary"; + +type BadgeProps = HTMLAttributes & { + tone?: BadgeTone; +}; + +export function Badge({ tone = "default", className, ...props }: BadgeProps) { + return ( + + ); +} diff --git a/codestory-ui/src/ui/primitives/Button.tsx b/codestory-ui/src/ui/primitives/Button.tsx new file mode 100644 index 0000000..7f09456 --- /dev/null +++ b/codestory-ui/src/ui/primitives/Button.tsx @@ -0,0 +1,39 @@ +import type { ButtonHTMLAttributes, ReactNode } from "react"; + +import { cx } from "./cx"; + +type ButtonVariant = "primary" | "secondary" | "ghost"; + +type ButtonProps = ButtonHTMLAttributes & { + variant?: ButtonVariant; + leadingIcon?: ReactNode; + trailingIcon?: ReactNode; +}; + +export function Button({ + variant = "secondary", + leadingIcon, + trailingIcon, + className, + children, + type = "button", + ...props +}: ButtonProps) { + return ( + + ); +} diff --git a/codestory-ui/src/ui/primitives/Card.tsx b/codestory-ui/src/ui/primitives/Card.tsx new file mode 100644 index 0000000..99a4f37 --- /dev/null +++ b/codestory-ui/src/ui/primitives/Card.tsx @@ -0,0 +1,24 @@ +import { createElement, type ElementType, type HTMLAttributes } from "react"; + +import { cx } from "./cx"; + +type CardTone = "default" | "accent" | "secondary" | "tertiary"; +type CardElement = "div" | "section" | "article"; + +type CardProps = HTMLAttributes & { + as?: CardElement; + tone?: CardTone; +}; + +export function Card({ as = "div", tone = "default", className, ...props }: CardProps) { + return createElement(as as ElementType, { + className: cx( + "ui-card", + tone === "accent" ? "ui-card-accent" : "", + tone === "secondary" ? "ui-card-secondary" : "", + tone === "tertiary" ? "ui-card-tertiary" : "", + className, + ), + ...props, + }); +} diff --git a/codestory-ui/src/ui/primitives/InputField.tsx b/codestory-ui/src/ui/primitives/InputField.tsx new file mode 100644 index 0000000..930934f --- /dev/null +++ b/codestory-ui/src/ui/primitives/InputField.tsx @@ -0,0 +1,29 @@ +import { useId, type InputHTMLAttributes } from "react"; + +import { cx } from "./cx"; + +type InputFieldProps = InputHTMLAttributes & { + label?: string; + hint?: string; + wrapperClassName?: string; +}; + +export function InputField({ + label, + hint, + wrapperClassName, + id, + className, + ...props +}: InputFieldProps) { + const generatedId = useId(); + const inputId = id ?? generatedId; + + return ( + + ); +} diff --git a/codestory-ui/src/ui/primitives/Panel.tsx b/codestory-ui/src/ui/primitives/Panel.tsx new file mode 100644 index 0000000..268d479 --- /dev/null +++ b/codestory-ui/src/ui/primitives/Panel.tsx @@ -0,0 +1,16 @@ +import { createElement, type ElementType, type HTMLAttributes } from "react"; + +import { cx } from "./cx"; + +type PanelElement = "section" | "div" | "article"; + +type PanelProps = HTMLAttributes & { + as?: T; +}; + +export function Panel({ as = "section", className, ...props }: PanelProps) { + return createElement(as as ElementType, { + className: cx("ui-panel", className), + ...props, + }); +} diff --git a/codestory-ui/src/ui/primitives/cx.ts b/codestory-ui/src/ui/primitives/cx.ts new file mode 100644 index 0000000..ef51566 --- /dev/null +++ b/codestory-ui/src/ui/primitives/cx.ts @@ -0,0 +1,3 @@ +export function cx(...parts: Array): string { + return parts.filter(Boolean).join(" "); +} diff --git a/codestory-ui/src/ui/primitives/index.ts b/codestory-ui/src/ui/primitives/index.ts new file mode 100644 index 0000000..23b1237 --- /dev/null +++ b/codestory-ui/src/ui/primitives/index.ts @@ -0,0 +1,5 @@ +export { Badge } from "./Badge"; +export { Button } from "./Button"; +export { Card } from "./Card"; +export { InputField } from "./InputField"; +export { Panel } from "./Panel"; diff --git a/codestory-ui/tests/app/canonicalUi.test.ts b/codestory-ui/tests/app/canonicalUi.test.ts new file mode 100644 index 0000000..814710d --- /dev/null +++ b/codestory-ui/tests/app/canonicalUi.test.ts @@ -0,0 +1,22 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +import { describe, expect, it } from "vitest"; + +describe("canonical ui without feature flags", () => { + it("does not reference feature-flag keys in App", () => { + const appPath = join(process.cwd(), "src", "App.tsx"); + const source = readFileSync(appPath, "utf8"); + expect(source).not.toContain("uxResetV2"); + expect(source).not.toContain("singlePaneInvestigate"); + expect(source).not.toContain("spacesLibrary"); + expect(source).not.toContain("onboardingStarter"); + }); + + it("does not render settings toggles anymore", () => { + const settingsPath = join(process.cwd(), "src", "features", "settings", "SettingsPage.tsx"); + const source = readFileSync(settingsPath, "utf8"); + expect(source).not.toContain('type="checkbox"'); + expect(source).toContain("Playful Geometric theme"); + }); +}); diff --git a/codestory-ui/tests/app/featureFlags.test.ts b/codestory-ui/tests/app/featureFlags.test.ts deleted file mode 100644 index 3646655..0000000 --- a/codestory-ui/tests/app/featureFlags.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { normalizeFeatureFlags } from "../../src/app/featureFlags"; - -describe("featureFlags", () => { - it("uses defaults when payload missing", () => { - expect(normalizeFeatureFlags(null)).toEqual({ - uxResetV2: true, - onboardingStarter: true, - singlePaneInvestigate: true, - spacesLibrary: true, - }); - }); - - it("migrates legacy keys", () => { - expect( - normalizeFeatureFlags({ modernShell: false, onboarding: false, spacesLibrary: true }), - ).toEqual({ - uxResetV2: false, - onboardingStarter: false, - singlePaneInvestigate: true, - spacesLibrary: true, - }); - }); - - it("prefers v2 keys when present", () => { - expect( - normalizeFeatureFlags({ - modernShell: false, - onboarding: false, - uxResetV2: true, - onboardingStarter: true, - singlePaneInvestigate: false, - spacesLibrary: false, - }), - ).toEqual({ - uxResetV2: true, - onboardingStarter: true, - singlePaneInvestigate: false, - spacesLibrary: false, - }); - }); -}); diff --git a/codestory-ui/tests/app/themeTokens.test.ts b/codestory-ui/tests/app/themeTokens.test.ts new file mode 100644 index 0000000..fec4d76 --- /dev/null +++ b/codestory-ui/tests/app/themeTokens.test.ts @@ -0,0 +1,30 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +import { describe, expect, it } from "vitest"; + +import { EDGE_KIND_COLORS, GRAPH_THEME, PLAYFUL_TOKENS } from "../../src/theme/tokens"; + +describe("theme token contract", () => { + it("exposes the Playful Geometric core palette and radii", () => { + expect(PLAYFUL_TOKENS.colors.background).toBe("#FFFDF5"); + expect(PLAYFUL_TOKENS.colors.accent).toBe("#8B5CF6"); + expect(PLAYFUL_TOKENS.radius.md).toBe("16px"); + expect(PLAYFUL_TOKENS.motion.bounce).toContain("cubic-bezier"); + }); + + it("maps graph semantics to stable edge colors", () => { + expect(EDGE_KIND_COLORS.CALL).toBeDefined(); + expect(EDGE_KIND_COLORS.INHERITANCE).toBeDefined(); + expect(EDGE_KIND_COLORS.UNKNOWN).toBeDefined(); + expect(GRAPH_THEME.minimap.background).toContain("rgb"); + }); + + it("defines css variables in tokens.css", () => { + const cssPath = join(process.cwd(), "src", "theme", "tokens.css"); + const css = readFileSync(cssPath, "utf8"); + expect(css).toContain("--color-background"); + expect(css).toContain("--shadow-pop"); + expect(css).toContain("--graph-canvas-top"); + }); +});