@checkflow/sdk 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +63 -219
  2. package/dist/chunk-6EVTRC5X.mjs +59 -0
  3. package/dist/chunk-CD33QAA6.mjs +131 -0
  4. package/dist/highlighter-Dx2zURb6.d.mts +73 -0
  5. package/dist/highlighter-Dx2zURb6.d.ts +73 -0
  6. package/dist/highlighter-W4XDALRE.mjs +8 -0
  7. package/dist/index.d.mts +46 -0
  8. package/dist/index.d.ts +43 -20
  9. package/dist/index.js +974 -17219
  10. package/dist/index.mjs +802 -0
  11. package/dist/react.d.mts +28 -0
  12. package/dist/react.d.ts +28 -0
  13. package/dist/react.js +1118 -0
  14. package/dist/react.mjs +51 -0
  15. package/dist/screenshot-HXKGZNCZ.mjs +10 -0
  16. package/dist/vue.d.mts +26 -0
  17. package/dist/vue.d.ts +26 -0
  18. package/dist/vue.js +1119 -0
  19. package/dist/vue.mjs +53 -0
  20. package/package.json +38 -53
  21. package/dist/analytics-tracker.d.ts +0 -112
  22. package/dist/annotation/editor.d.ts +0 -72
  23. package/dist/annotation/index.d.ts +0 -9
  24. package/dist/annotation/styles.d.ts +0 -6
  25. package/dist/annotation/toolbar.d.ts +0 -32
  26. package/dist/annotation/types.d.ts +0 -85
  27. package/dist/api-client.d.ts +0 -76
  28. package/dist/checkflow.css +0 -1
  29. package/dist/checkflow.d.ts +0 -112
  30. package/dist/context-capture.d.ts +0 -42
  31. package/dist/error-capture.d.ts +0 -60
  32. package/dist/index.esm.js +0 -17210
  33. package/dist/index.esm.js.map +0 -1
  34. package/dist/index.js.map +0 -1
  35. package/dist/optimized-recorder.d.ts +0 -94
  36. package/dist/privacy/detector.d.ts +0 -56
  37. package/dist/privacy/index.d.ts +0 -8
  38. package/dist/privacy/masker.d.ts +0 -43
  39. package/dist/privacy/types.d.ts +0 -54
  40. package/dist/react/index.d.ts +0 -77
  41. package/dist/session-recording-rrweb.d.ts +0 -100
  42. package/dist/session-recording.d.ts +0 -74
  43. package/dist/types.d.ts +0 -299
  44. package/dist/vue/index.d.ts +0 -55
  45. package/dist/widget/Widget.d.ts +0 -98
  46. package/dist/widget/index.d.ts +0 -2
package/dist/vue.mjs ADDED
@@ -0,0 +1,53 @@
1
+ // src/vue.ts
2
+ var _config = null;
3
+ var _initialized = false;
4
+ function createCheckflowPlugin(config) {
5
+ return {
6
+ install() {
7
+ if (typeof window === "undefined") return;
8
+ if (_initialized) return;
9
+ _initialized = true;
10
+ _config = config;
11
+ import("./index.mjs").then(({ init }) => init(config));
12
+ }
13
+ };
14
+ }
15
+ function useCheckflow() {
16
+ return {
17
+ send: async (data) => {
18
+ if (typeof window === "undefined") return { success: false, error: { message: "Not in browser", code: "SSR" } };
19
+ const { sendFeedback } = await import("./index.mjs");
20
+ return sendFeedback(data);
21
+ },
22
+ screenshot: async () => {
23
+ if (typeof window === "undefined") return null;
24
+ const { captureScreenshot } = await import("./screenshot-HXKGZNCZ.mjs");
25
+ return captureScreenshot();
26
+ },
27
+ highlight: async () => {
28
+ if (typeof window === "undefined") return [];
29
+ const { startHighlighting } = await import("./highlighter-W4XDALRE.mjs");
30
+ return startHighlighting();
31
+ },
32
+ show: async () => {
33
+ if (typeof window === "undefined") return;
34
+ const { showWidget } = await import("./index.mjs");
35
+ showWidget();
36
+ },
37
+ hide: async () => {
38
+ if (typeof window === "undefined") return;
39
+ const { hideWidget } = await import("./index.mjs");
40
+ hideWidget();
41
+ },
42
+ destroy: async () => {
43
+ if (typeof window === "undefined") return;
44
+ const { destroy } = await import("./index.mjs");
45
+ destroy();
46
+ _initialized = false;
47
+ }
48
+ };
49
+ }
50
+ export {
51
+ createCheckflowPlugin,
52
+ useCheckflow
53
+ };
package/package.json CHANGED
@@ -1,72 +1,57 @@
1
1
  {
2
2
  "name": "@checkflow/sdk",
3
- "version": "1.1.1",
4
- "type": "module",
5
- "description": "CheckFlow SDK for capturing user feedback with context",
3
+ "version": "1.1.3",
4
+ "description": "Lightweight bug reporter & feedback SDK for Checkflow — with screenshot capture, element highlighting, and framework integrations",
6
5
  "main": "dist/index.js",
7
- "module": "dist/index.esm.js",
6
+ "module": "dist/index.mjs",
8
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./react": {
15
+ "types": "./dist/react.d.ts",
16
+ "import": "./dist/react.mjs",
17
+ "require": "./dist/react.js"
18
+ },
19
+ "./vue": {
20
+ "types": "./dist/vue.d.ts",
21
+ "import": "./dist/vue.mjs",
22
+ "require": "./dist/vue.js"
23
+ }
24
+ },
9
25
  "files": [
10
- "dist",
11
- "README.md"
26
+ "dist"
12
27
  ],
13
28
  "scripts": {
14
- "build": "rollup -c rollup.config.mjs",
15
- "build:watch": "rollup -c -w",
16
- "test": "jest",
17
- "lint": "eslint src --ext .ts,.tsx",
18
- "prepublishOnly": "npm run build"
29
+ "build": "tsup src/index.ts src/react.ts src/vue.ts --format cjs,esm --dts --clean",
30
+ "dev": "tsup src/index.ts src/react.ts src/vue.ts --format cjs,esm --dts --watch"
19
31
  },
20
32
  "keywords": [
33
+ "checkflow",
34
+ "bug-tracker",
21
35
  "feedback",
22
- "bug-report",
36
+ "sdk",
23
37
  "screenshot",
24
- "context-capture",
25
- "error-tracking",
26
- "user-feedback"
38
+ "highlight",
39
+ "react",
40
+ "nextjs",
41
+ "vue",
42
+ "nuxt"
27
43
  ],
28
- "author": "checkFlow",
29
44
  "license": "MIT",
30
- "repository": {
31
- "type": "git",
32
- "url": "git+https://github.com/checkflow/checkflow-sdk.git"
33
- },
34
- "devDependencies": {
35
- "@rollup/plugin-commonjs": "^25.0.7",
36
- "@rollup/plugin-node-resolve": "^15.2.3",
37
- "@rollup/plugin-typescript": "^11.1.5",
38
- "@types/jest": "^29.5.11",
39
- "@types/node": "^20.10.5",
40
- "@types/pako": "^2.0.4",
41
- "@types/react": "^18.3.27",
42
- "@types/react-dom": "^18.3.7",
43
- "@typescript-eslint/eslint-plugin": "^6.15.0",
44
- "@typescript-eslint/parser": "^6.15.0",
45
- "eslint": "^8.56.0",
46
- "jest": "^29.7.0",
47
- "rollup": "^4.9.1",
48
- "rollup-plugin-dts": "^6.1.0",
49
- "rollup-plugin-postcss": "^4.0.2",
50
- "ts-jest": "^29.1.1",
51
- "tslib": "^2.6.2",
52
- "typescript": "^5.3.3",
53
- "vue": "^3.5.25"
54
- },
55
- "dependencies": {
56
- "html2canvas": "^1.4.1",
57
- "pako": "^2.1.0",
58
- "rrweb": "^2.0.0-alpha.17"
59
- },
60
45
  "peerDependencies": {
61
- "react": ">=16.8.0",
46
+ "react": ">=17.0.0",
62
47
  "vue": ">=3.0.0"
63
48
  },
64
49
  "peerDependenciesMeta": {
65
- "react": {
66
- "optional": true
67
- },
68
- "vue": {
69
- "optional": true
70
- }
50
+ "react": { "optional": true },
51
+ "vue": { "optional": true }
52
+ },
53
+ "devDependencies": {
54
+ "tsup": "^8.0.0",
55
+ "typescript": "^5.3.0"
71
56
  }
72
57
  }
@@ -1,112 +0,0 @@
1
- /**
2
- * Analytics Tracker for CheckFlow SDK
3
- * Automatically tracks user sessions and interactions for analytics
4
- */
5
- import { APIClient } from './api-client';
6
- export interface SessionData {
7
- sessionId: string;
8
- projectId: string;
9
- userFingerprint?: string;
10
- ipAddress?: string;
11
- country?: string;
12
- region?: string;
13
- city?: string;
14
- latitude?: number;
15
- longitude?: number;
16
- userAgent?: string;
17
- viewport?: ViewportInfo;
18
- browser?: string;
19
- os?: string;
20
- locale?: string;
21
- timezone?: string;
22
- entryUrl?: string;
23
- referrer?: string;
24
- }
25
- export interface ViewportInfo {
26
- width: number;
27
- height: number;
28
- device: 'desktop' | 'mobile' | 'tablet';
29
- }
30
- export interface InteractionEvent {
31
- pageUrl: string;
32
- pageTitle?: string;
33
- eventType: 'page_view' | 'click' | 'scroll' | 'form_interaction' | 'error';
34
- elementSelector?: string;
35
- elementText?: string;
36
- mouseX?: number;
37
- mouseY?: number;
38
- scrollDepth?: number;
39
- loadTime?: number;
40
- domReadyTime?: number;
41
- errorMessage?: string;
42
- errorStack?: string;
43
- }
44
- export interface AnalyticsOptions {
45
- batchSize: number;
46
- batchTimeout: number;
47
- trackClicks: boolean;
48
- trackScrolling: boolean;
49
- trackFormInteractions: boolean;
50
- trackErrors: boolean;
51
- trackPerformance: boolean;
52
- throttleScrollMs: number;
53
- maxScrollEvents: number;
54
- debug: boolean;
55
- }
56
- export declare class AnalyticsTracker {
57
- private apiClient;
58
- private options;
59
- private sessionId;
60
- private projectId;
61
- private userFingerprint;
62
- private isActive;
63
- private sessionStartTime;
64
- private currentPageUrl;
65
- private pageLoadStart;
66
- private interactionBuffer;
67
- private batchTimer;
68
- private scrollEvents;
69
- private lastScrollTime;
70
- private isFirstPageView;
71
- private performanceObserver?;
72
- private recordingUploadTimer;
73
- private readonly RECORDING_UPLOAD_INTERVAL;
74
- constructor(apiClient: APIClient, options?: Partial<AnalyticsOptions>);
75
- startTracking(): Promise<void>;
76
- stopTracking(): Promise<void>;
77
- private saveSessionRecording;
78
- private setupPeriodicRecordingUpload;
79
- private createSession;
80
- private updateSessionEnd;
81
- private setupEventListeners;
82
- private removeEventListeners;
83
- private handleClick;
84
- private handleScroll;
85
- private handleFormFocus;
86
- private handleFormChange;
87
- private handleError;
88
- private handleUnhandledRejection;
89
- private handlePageUnload;
90
- private handleVisibilityChange;
91
- private setupSPATracking;
92
- private setupPerformanceTracking;
93
- private trackPageView;
94
- private capturePageScreenshotForHeatmap;
95
- private trackPageLoadPerformance;
96
- private queueInteraction;
97
- private flushInteractions;
98
- private generateSessionId;
99
- private generateUserFingerprint;
100
- private getGeolocation;
101
- private getViewportInfo;
102
- private getBrowserInfo;
103
- private getOSInfo;
104
- private getElementSelector;
105
- private getElementText;
106
- private isFormElement;
107
- private calculateScrollDepth;
108
- private getPageLoadTime;
109
- private getDOMReadyTime;
110
- private getPageViewCount;
111
- private log;
112
- }
@@ -1,72 +0,0 @@
1
- /**
2
- * CheckFlow Annotation Editor
3
- * Figma-like canvas editor for annotating screenshots
4
- */
5
- import { Annotation, AnnotationEditorConfig } from './types';
6
- export declare class AnnotationEditor {
7
- private container;
8
- private canvas;
9
- private ctx;
10
- private toolbar;
11
- private config;
12
- private annotations;
13
- private backgroundImage;
14
- private state;
15
- private startPoint;
16
- private freehandPoints;
17
- private textInput;
18
- constructor(config: AnnotationEditorConfig);
19
- /**
20
- * Open the annotation editor with a screenshot
21
- */
22
- open(screenshotDataUrl: string): Promise<void>;
23
- /**
24
- * Close the editor
25
- */
26
- close(): void;
27
- /**
28
- * Get the annotated image as data URL
29
- */
30
- getAnnotatedImage(): string;
31
- /**
32
- * Get annotations data
33
- */
34
- getAnnotations(): Annotation[];
35
- private loadImage;
36
- private createEditorUI;
37
- private setupEventListeners;
38
- private handleMouseDown;
39
- private handleMouseMove;
40
- private handleMouseUp;
41
- private handleTouchStart;
42
- private handleTouchMove;
43
- private handleTouchEnd;
44
- private handleKeyDown;
45
- private getCanvasPoint;
46
- private getCanvasPointFromTouch;
47
- private startDrawing;
48
- private continueDrawing;
49
- private finishDrawing;
50
- private isValidAnnotation;
51
- private createAnnotation;
52
- private createBounds;
53
- private showTextInput;
54
- private generateId;
55
- private setActiveTool;
56
- private setStyle;
57
- private undo;
58
- private clearAll;
59
- private save;
60
- private cancel;
61
- private render;
62
- private drawAnnotations;
63
- private drawAnnotation;
64
- private drawRectangle;
65
- private drawEllipse;
66
- private drawArrow;
67
- private drawLine;
68
- private drawHighlight;
69
- private drawBlur;
70
- private drawText;
71
- private drawFreehand;
72
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * CheckFlow Annotation Module
3
- * Figma-like annotation tools for feedback screenshots
4
- */
5
- export { AnnotationEditor } from './editor';
6
- export { AnnotationToolbar } from './toolbar';
7
- export { injectAnnotationStyles, removeAnnotationStyles } from './styles';
8
- export type { AnnotationToolType, Point, Bounds, AnnotationStyle, Annotation, RectangleAnnotation, EllipseAnnotation, ArrowAnnotation, LineAnnotation, HighlightAnnotation, BlurAnnotation, TextAnnotation, FreehandAnnotation, AnnotationEditorConfig, ToolState, } from './types';
9
- export { DEFAULT_STYLE, HIGHLIGHT_STYLE, BLUR_STYLE, COLOR_PALETTE, STROKE_WIDTHS, } from './types';
@@ -1,6 +0,0 @@
1
- /**
2
- * CheckFlow Annotation Styles
3
- * CSS-in-JS styles for the annotation editor
4
- */
5
- export declare function injectAnnotationStyles(): void;
6
- export declare function removeAnnotationStyles(): void;
@@ -1,32 +0,0 @@
1
- /**
2
- * CheckFlow Annotation Toolbar
3
- * Figma-like floating toolbar for annotation tools
4
- */
5
- import { AnnotationToolType, AnnotationStyle } from './types';
6
- export interface ToolbarConfig {
7
- tools: AnnotationToolType[];
8
- activeTool: AnnotationToolType;
9
- style: AnnotationStyle;
10
- onToolChange: (tool: AnnotationToolType) => void;
11
- onStyleChange: (style: Partial<AnnotationStyle>) => void;
12
- onUndo: () => void;
13
- onClear: () => void;
14
- onSave: () => void;
15
- onCancel: () => void;
16
- }
17
- export declare class AnnotationToolbar {
18
- private element;
19
- private config;
20
- private colorPicker;
21
- private strokePicker;
22
- constructor(config: ToolbarConfig);
23
- getElement(): HTMLElement;
24
- setActiveTool(tool: AnnotationToolType): void;
25
- setStyle(style: AnnotationStyle): void;
26
- private createToolbar;
27
- private createToolButton;
28
- private updateActiveState;
29
- private updateStyleDisplay;
30
- private toggleColorPicker;
31
- private toggleStrokePicker;
32
- }
@@ -1,85 +0,0 @@
1
- /**
2
- * CheckFlow Annotation System Types
3
- * Figma-like annotation tools for feedback screenshots
4
- */
5
- export type AnnotationToolType = 'select' | 'rectangle' | 'ellipse' | 'arrow' | 'line' | 'highlight' | 'blur' | 'text' | 'freehand';
6
- export interface Point {
7
- x: number;
8
- y: number;
9
- }
10
- export interface Bounds {
11
- x: number;
12
- y: number;
13
- width: number;
14
- height: number;
15
- }
16
- export interface AnnotationStyle {
17
- strokeColor: string;
18
- strokeWidth: number;
19
- fillColor: string;
20
- opacity: number;
21
- fontSize?: number;
22
- fontFamily?: string;
23
- }
24
- export interface BaseAnnotation {
25
- id: string;
26
- type: AnnotationToolType;
27
- style: AnnotationStyle;
28
- timestamp: number;
29
- }
30
- export interface RectangleAnnotation extends BaseAnnotation {
31
- type: 'rectangle';
32
- bounds: Bounds;
33
- }
34
- export interface EllipseAnnotation extends BaseAnnotation {
35
- type: 'ellipse';
36
- bounds: Bounds;
37
- }
38
- export interface ArrowAnnotation extends BaseAnnotation {
39
- type: 'arrow';
40
- start: Point;
41
- end: Point;
42
- }
43
- export interface LineAnnotation extends BaseAnnotation {
44
- type: 'line';
45
- start: Point;
46
- end: Point;
47
- }
48
- export interface HighlightAnnotation extends BaseAnnotation {
49
- type: 'highlight';
50
- bounds: Bounds;
51
- }
52
- export interface BlurAnnotation extends BaseAnnotation {
53
- type: 'blur';
54
- bounds: Bounds;
55
- blurAmount: number;
56
- }
57
- export interface TextAnnotation extends BaseAnnotation {
58
- type: 'text';
59
- position: Point;
60
- text: string;
61
- }
62
- export interface FreehandAnnotation extends BaseAnnotation {
63
- type: 'freehand';
64
- points: Point[];
65
- }
66
- export type Annotation = RectangleAnnotation | EllipseAnnotation | ArrowAnnotation | LineAnnotation | HighlightAnnotation | BlurAnnotation | TextAnnotation | FreehandAnnotation;
67
- export interface AnnotationEditorConfig {
68
- tools: AnnotationToolType[];
69
- defaultStyle: AnnotationStyle;
70
- canvasWidth?: number;
71
- canvasHeight?: number;
72
- onSave?: (annotations: Annotation[], imageData: string) => void;
73
- onCancel?: () => void;
74
- }
75
- export interface ToolState {
76
- activeTool: AnnotationToolType;
77
- style: AnnotationStyle;
78
- isDrawing: boolean;
79
- currentAnnotation: Annotation | null;
80
- }
81
- export declare const DEFAULT_STYLE: AnnotationStyle;
82
- export declare const HIGHLIGHT_STYLE: Partial<AnnotationStyle>;
83
- export declare const BLUR_STYLE: Partial<AnnotationStyle>;
84
- export declare const COLOR_PALETTE: string[];
85
- export declare const STROKE_WIDTHS: number[];
@@ -1,76 +0,0 @@
1
- /**
2
- * CheckFlow API Client
3
- * Handles all communication with the CheckFlow backend
4
- */
5
- import { APIResponse, FeedbackData, SubmitResult, CaptureResult, UserInfo } from './types';
6
- export interface APIClientOptions {
7
- apiUrl: string;
8
- apiKey: string;
9
- projectId?: string;
10
- timeout?: number;
11
- debug?: boolean;
12
- }
13
- export declare class APIClient {
14
- private apiUrl;
15
- private apiKey;
16
- private projectId?;
17
- private timeout;
18
- private debug;
19
- constructor(options: APIClientOptions);
20
- getProjectId(): string | undefined;
21
- getBaseUrl(): string;
22
- private log;
23
- get<T>(endpoint: string, headers?: Record<string, string>): Promise<APIResponse<T>>;
24
- post<T>(endpoint: string, data?: any, headers?: Record<string, string>): Promise<APIResponse<T>>;
25
- put<T>(endpoint: string, data?: any, headers?: Record<string, string>): Promise<APIResponse<T>>;
26
- private request;
27
- /**
28
- * Submit feedback to the backend
29
- */
30
- submitFeedback(feedback: FeedbackData, capture?: CaptureResult, user?: UserInfo, sessionRecording?: {
31
- events: any[];
32
- sessionId: string;
33
- }, annotations?: any[]): Promise<SubmitResult>;
34
- /**
35
- * Upload screenshot as attachment
36
- */
37
- uploadScreenshot(feedbackId: string, base64Image: string): Promise<APIResponse>;
38
- /**
39
- * Send SDK capture data to backend for processing
40
- * Aligns with backend SDKCapturePayload schema
41
- */
42
- sendCapture(capture: CaptureResult, sessionId?: string): Promise<APIResponse>;
43
- /**
44
- * Upload just a screenshot (simpler endpoint)
45
- */
46
- uploadScreenshotOnly(screenshotBase64: string, url: string): Promise<APIResponse>;
47
- /**
48
- * Save session recording to analytics backend
49
- * Recordings are now part of analytics sessions (independent from feedbacks)
50
- */
51
- saveSessionRecording(recording: {
52
- events: any[];
53
- sessionId: string;
54
- durationMs?: number;
55
- }): Promise<APIResponse>;
56
- /**
57
- * Report an error to the backend
58
- */
59
- reportError(error: {
60
- message: string;
61
- stack?: string;
62
- type: string;
63
- filename?: string;
64
- lineno?: number;
65
- colno?: number;
66
- context?: any;
67
- }): Promise<APIResponse>;
68
- /**
69
- * Check API health
70
- */
71
- healthCheck(): Promise<boolean>;
72
- /**
73
- * Update project ID
74
- */
75
- setProjectId(projectId: string): void;
76
- }
@@ -1 +0,0 @@
1
- .checkflow-widget{--cf-bg:#fff;--cf-bg-elevated:#fafafa;--cf-bg-hover:#f5f5f5;--cf-text:#18181b;--cf-text-secondary:#71717a;--cf-text-muted:#a1a1aa;--cf-border:#e4e4e7;--cf-border-light:#f4f4f5;--cf-accent:#18181b;--cf-accent-hover:#27272a;--cf-success:#22c55e;--cf-error:#ef4444;--cf-shadow-sm:0 1px 2px rgba(0,0,0,.05);--cf-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--cf-shadow-lg:0 10px 40px -10px rgba(0,0,0,.2);--cf-radius:16px;--cf-radius-sm:8px;--cf-radius-xs:6px;-webkit-font-smoothing:antialiased;color:var(--cf-text);font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.5}.checkflow-widget,.checkflow-widget *,.checkflow-widget :after,.checkflow-widget :before{box-sizing:border-box}.checkflow-trigger{align-items:center;background:var(--cf-accent);border:none;border-radius:50%;box-shadow:var(--cf-shadow-lg);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;position:fixed;transition:all .3s cubic-bezier(.4,0,.2,1);width:56px;z-index:999998}.checkflow-trigger-pill{background:#fff;border-radius:24px;box-shadow:0 4px 20px rgba(0,0,0,.1),0 0 0 1px rgba(0,0,0,.05);color:#18181b;gap:8px;height:48px;min-width:160px;padding:0 20px;width:auto}.checkflow-trigger-pill:hover{box-shadow:0 8px 25px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.05);transform:translateY(-1px)}.checkflow-trigger-pill:active{transform:translateY(0)}.checkflow-trigger.bottom-right{bottom:24px;right:24px}.checkflow-trigger.bottom-left{bottom:24px;left:24px}.checkflow-trigger.top-right{right:24px;top:24px}.checkflow-trigger.top-left{left:24px;top:24px}.checkflow-trigger-icon{flex-shrink:0;height:20px;transition:transform .3s ease;width:20px}.checkflow-trigger-text{font-size:14px;font-weight:500;white-space:nowrap}.checkflow-trigger:hover .checkflow-trigger-icon{transform:rotate(-8deg)}.checkflow-panel{animation:cf-panel-in .3s cubic-bezier(.4,0,.2,1);background:var(--cf-bg);border:1px solid var(--cf-border-light);border-radius:var(--cf-radius);bottom:96px;box-shadow:var(--cf-shadow-lg);display:flex;flex-direction:column;max-height:calc(100vh - 140px);overflow:hidden;position:fixed;right:24px;width:380px;z-index:999999}.checkflow-panel.bottom-left{left:24px;right:auto}@keyframes cf-panel-in{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.checkflow-header{align-items:center;background:var(--cf-bg);border-bottom:1px solid var(--cf-border-light);display:flex;justify-content:space-between;padding:16px 20px}.checkflow-header-left{align-items:center;display:flex;gap:12px}.checkflow-logo{align-items:center;background:var(--cf-accent);border-radius:8px;color:#fff;display:flex;height:32px;justify-content:center;width:32px}.checkflow-header-text h3{color:var(--cf-text);font-size:15px;font-weight:600;margin:0}.checkflow-header-text p{color:var(--cf-text-muted);font-size:12px;margin:0}.checkflow-close{align-items:center;background:transparent;border:none;border-radius:8px;color:var(--cf-text-secondary);cursor:pointer;display:flex;height:32px;justify-content:center;transition:all .2s;width:32px}.checkflow-close:hover{background:var(--cf-bg-hover);color:var(--cf-text)}.checkflow-body{flex:1;max-height:480px;overflow-y:auto;padding:20px}.checkflow-form{gap:16px}.checkflow-field,.checkflow-form{display:flex;flex-direction:column}.checkflow-field{gap:6px}.checkflow-label{color:var(--cf-text);font-size:13px;font-weight:500}.cf-required{color:var(--cf-text-muted);font-size:12px;font-weight:400}.checkflow-input,.checkflow-select,.checkflow-textarea{background:var(--cf-bg);border:1px solid var(--cf-border);border-radius:var(--cf-radius-sm);color:var(--cf-text);font-size:14px;padding:12px 14px;transition:all .2s}.checkflow-input::placeholder,.checkflow-textarea::placeholder{color:var(--cf-text-muted)}.checkflow-input:focus,.checkflow-select:focus,.checkflow-textarea:focus{border-color:var(--cf-accent);box-shadow:0 0 0 3px rgba(24,24,27,.08);outline:none}.checkflow-textarea{font-family:inherit;min-height:80px;resize:none}.checkflow-select{appearance:none;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-position:right 12px center;background-repeat:no-repeat;cursor:pointer;padding-right:40px}.checkflow-type-grid{display:flex;flex-wrap:wrap;gap:8px}.checkflow-type-option{align-items:center;background:var(--cf-bg);border:1px solid var(--cf-border);border-radius:20px;cursor:pointer;display:flex;font-size:13px;gap:6px;padding:8px 14px;transition:all .2s}.checkflow-type-option:hover{background:var(--cf-bg-hover);border-color:var(--cf-text-muted)}.checkflow-type-option.selected{background:var(--cf-accent);border-color:var(--cf-accent);color:#fff}.checkflow-type-icon{font-size:14px;line-height:1}.checkflow-type-label{font-size:13px;font-weight:500}.checkflow-screenshot{background:var(--cf-bg-elevated);border-radius:var(--cf-radius-sm);overflow:hidden;position:relative}.checkflow-screenshot img{display:block;height:auto;width:100%}.checkflow-screenshot-actions{bottom:10px;display:flex;gap:6px;position:absolute;right:10px}.checkflow-screenshot-btn{align-items:center;backdrop-filter:blur(8px);background:hsla(0,0%,100%,.95);border:none;border-radius:6px;box-shadow:0 2px 8px rgba(0,0,0,.1);color:var(--cf-text);cursor:pointer;display:flex;font-size:11px;font-weight:500;gap:5px;padding:6px 10px;transition:all .2s}.checkflow-screenshot-btn:hover{background:#fff;box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.checkflow-screenshot-btn svg{height:12px;width:12px}.checkflow-annotate-btn{background:var(--cf-accent);color:#fff}.checkflow-annotate-btn:hover{background:var(--cf-accent-hover)}.checkflow-checkbox{align-items:center;cursor:pointer;display:flex;gap:10px;padding:8px 0}.checkflow-checkbox input{accent-color:var(--cf-accent);cursor:pointer;height:18px;width:18px}.checkflow-checkbox-label{color:var(--cf-text-secondary);font-size:13px}.checkflow-footer{background:var(--cf-bg);border-top:1px solid var(--cf-border-light);display:flex;gap:10px;padding:16px 20px}.checkflow-btn{border-radius:var(--cf-radius-sm);cursor:pointer;flex:1;font-size:14px;font-weight:500;padding:12px 16px;text-align:center;transition:all .2s}.checkflow-btn-secondary{background:var(--cf-bg);border:1px solid var(--cf-border);color:var(--cf-text-secondary)}.checkflow-btn-secondary:hover{background:var(--cf-bg-hover);color:var(--cf-text)}.checkflow-btn-primary{background:var(--cf-accent);border:none;color:#fff}.checkflow-btn-primary:hover{background:var(--cf-accent-hover)}.checkflow-btn-primary:disabled{background:var(--cf-border);color:var(--cf-text-muted);cursor:not-allowed}.checkflow-loading{align-items:center;display:flex;flex-direction:column;gap:16px;justify-content:center;padding:48px 20px}.checkflow-spinner{animation:cf-spin .7s linear infinite;border:2px solid var(--cf-border);border-radius:50%;border-top-color:var(--cf-accent);height:28px;width:28px}@keyframes cf-spin{to{transform:rotate(1turn)}}.checkflow-loading-text{color:var(--cf-text-muted);font-size:13px}.checkflow-success{padding:48px 24px;text-align:center}.checkflow-success-icon{align-items:center;background:linear-gradient(135deg,#22c55e,#16a34a);border-radius:50%;color:#fff;display:flex;font-size:28px;height:56px;justify-content:center;margin:0 auto 20px;width:56px}.checkflow-success-title{color:var(--cf-text);font-size:17px;font-weight:600;margin:0 0 8px}.checkflow-success-message{color:var(--cf-text-secondary);font-size:14px;line-height:1.6;margin:0}.checkflow-error{align-items:flex-start;background:#fef2f2;border:1px solid #fecaca;border-radius:var(--cf-radius-sm);color:#dc2626;display:flex;font-size:13px;gap:10px;margin-bottom:16px;padding:12px 14px}.checkflow-error-icon{flex-shrink:0;height:18px;width:18px}.checkflow-capture-btn{align-items:center;background:var(--cf-bg-elevated);border:1px dashed var(--cf-border);border-radius:var(--cf-radius-sm);color:var(--cf-text-secondary);cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:8px;justify-content:center;padding:14px;transition:all .2s;width:100%}.checkflow-capture-btn:hover{background:var(--cf-bg-hover);border-color:var(--cf-text-muted);color:var(--cf-text)}.checkflow-capture-btn svg{height:18px;width:18px}.checkflow-options{display:flex;flex-wrap:wrap;gap:16px;padding-top:4px}.checkflow-divider{background:var(--cf-border-light);height:1px;margin:8px 0}.checkflow-powered{border-top:1px solid var(--cf-border-light);color:var(--cf-text-muted);font-size:11px;padding:12px;text-align:center}.checkflow-powered a{color:var(--cf-text-secondary);font-weight:500;text-decoration:none}.checkflow-powered a:hover{color:var(--cf-text)}@media (max-width:480px){.checkflow-panel{bottom:80px;max-height:calc(100vh - 100px);right:16px;width:calc(100vw - 32px)}.checkflow-trigger{bottom:16px;height:52px;right:16px;width:52px}.checkflow-trigger.bottom-left{left:16px}}.checkflow-body::-webkit-scrollbar{width:6px}.checkflow-body::-webkit-scrollbar-track{background:transparent}.checkflow-body::-webkit-scrollbar-thumb{background:var(--cf-border);border-radius:3px}.checkflow-body::-webkit-scrollbar-thumb:hover{background:var(--cf-text-muted)}.checkflow-overlay{align-items:center;animation:cf-fade-in .2s ease;background:rgba(0,0,0,.5);bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999999}@keyframes cf-fade-in{0%{opacity:0}to{opacity:1}}.checkflow-modal-compact{animation:cf-modal-in .3s cubic-bezier(.4,0,.2,1);background:var(--cf-bg);border-radius:var(--cf-radius);box-shadow:var(--cf-shadow-lg);display:flex;flex-direction:column;max-height:90vh;max-width:90vw;overflow:hidden;width:420px}@keyframes cf-modal-in{0%{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}.checkflow-modal-compact .checkflow-header{padding:20px 24px}.checkflow-modal-compact .checkflow-header h3{font-size:18px;font-weight:600;margin:0}.checkflow-modal-compact .checkflow-body{max-height:none;padding:0 24px 24px}.checkflow-modal-compact .checkflow-footer{flex-direction:column;padding:20px 24px}.checkflow-modal-compact .checkflow-btn{width:100%}.checkflow-expanded{backdrop-filter:blur(4px);background:rgba(24,24,27,.8)}.checkflow-modal-expanded{animation:cf-modal-in .3s cubic-bezier(.4,0,.2,1);background:var(--cf-bg);border-radius:var(--cf-radius);box-shadow:0 25px 80px -20px rgba(0,0,0,.4);display:flex;flex-direction:column;height:90vh;max-height:800px;max-width:1200px;overflow:hidden;width:95vw}.checkflow-modal-expanded .checkflow-header{border-bottom:1px solid var(--cf-border-light);padding:16px 24px}.checkflow-modal-expanded .checkflow-header h3{font-size:16px;font-weight:600;margin:0}.checkflow-content-split{display:flex;flex:1;overflow:hidden}.checkflow-screenshot-area{background:#1a1a1a;display:flex;flex:1;flex-direction:column;position:relative}.checkflow-screenshot-container{align-items:center;display:flex;flex:1;justify-content:center;overflow:auto;padding:24px}.checkflow-screenshot-large{border-radius:8px;box-shadow:0 8px 32px rgba(0,0,0,.3);max-height:100%;max-width:100%;object-fit:contain}.checkflow-annotation-toolbar{background:rgba(0,0,0,.3);display:flex;gap:12px;justify-content:center;padding:16px}.checkflow-tool-btn{align-items:center;background:hsla(0,0%,100%,.1);border:1px solid hsla(0,0%,100%,.2);border-radius:8px;color:#fff;cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:8px;padding:10px 20px;transition:all .2s}.checkflow-tool-btn:hover{background:hsla(0,0%,100%,.2);border-color:hsla(0,0%,100%,.3)}.checkflow-tool-btn svg{height:16px;width:16px}.checkflow-tool-highlight{background:#7c3aed;border-color:#7c3aed}.checkflow-tool-highlight:hover{background:#6d28d9;border-color:#6d28d9}.checkflow-form-area{background:var(--cf-bg);border-left:1px solid var(--cf-border-light);display:flex;flex-direction:column;width:320px}.checkflow-form-area .checkflow-form{flex:1;overflow-y:auto;padding:20px}.checkflow-form-area .checkflow-textarea{min-height:100px}.checkflow-btn-link{background:none;border:none;color:var(--cf-text-muted);cursor:pointer;font-size:12px;padding:8px 0;text-decoration:underline;transition:color .2s}.checkflow-btn-link:hover{color:var(--cf-error)}.checkflow-footer-expanded{border-top:1px solid var(--cf-border-light);display:flex;flex-direction:column;gap:10px;padding:16px 20px}.checkflow-footer-expanded .checkflow-btn{width:100%}.checkflow-form-area .checkflow-type-grid{display:flex;flex-wrap:wrap;gap:6px}.checkflow-form-area .checkflow-type-option{font-size:12px;padding:6px 10px}.checkflow-form-area .checkflow-type-icon{display:none}@media (max-width:768px){.checkflow-modal-expanded{border-radius:0;height:100vh;max-height:none;max-width:none;width:100vw}.checkflow-content-split{flex-direction:column}.checkflow-screenshot-area{flex:0 0 50%}.checkflow-form-area{border-left:none;border-top:1px solid var(--cf-border-light);width:100%}}