issue-sticker 0.11.0 → 0.12.0
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.
- package/CHANGELOG.md +43 -0
- package/dist/_commonjsHelpers-DWwsNxpa.js +8 -0
- package/dist/{externalUserPayload-BbOEmKZD.js → externalUserPayload-DWcXyz2U.js} +1177 -326
- package/dist/index-DA6SoSp7.js +3009 -0
- package/dist/issue-sticker-headless-react.js +3 -3
- package/dist/issue-sticker-headless.js +136 -74
- package/dist/issue-sticker-react.js +1052 -683
- package/dist/{three-DQdLNs7v.js → three-B228j4M6.js} +9 -9
- package/dist/{tooltip-DSCAsWIp.js → tooltip-CT7e9xbU.js} +1 -1
- package/headless.d.ts +45 -0
- package/package.json +1 -1
|
@@ -15,35 +15,92 @@ var __privateWrapper = (obj, member, setter, getter) => ({
|
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
17
|
var _focused, _cleanup, _setup, _b, _provider, _providerCalled, _c, _online, _cleanup2, _setup2, _d, _gcTimeout, _e, _queryType, _initialState, _revertState, _cache, _client, _retryer, _defaultOptions, _abortSignalConsumed, _Query_instances, isInitialPausedFetch_fn, dispatch_fn, _f, _client2, _currentQuery, _currentQueryInitialState, _currentResult, _currentResultState, _currentResultOptions, _currentThenable, _selectError, _selectFn, _selectResult, _lastQueryWithDefinedData, _staleTimeoutId, _refetchIntervalId, _currentRefetchInterval, _trackedProps, _QueryObserver_instances, executeFetch_fn, updateStaleTimeout_fn, computeRefetchInterval_fn, updateRefetchInterval_fn, updateTimers_fn, clearStaleTimeout_fn, clearRefetchInterval_fn, updateQuery_fn, notify_fn, _g, _client3, _observers, _mutationCache, _retryer2, _Mutation_instances, dispatch_fn2, _h, _mutations, _scopes, _mutationId, _i, _client4, _currentResult2, _currentMutation, _mutateOptions, _MutationObserver_instances, updateResult_fn, notify_fn2, _j, _queries, _k, _queryCache, _mutationCache2, _defaultOptions2, _queryDefaults, _mutationDefaults, _mountCount, _unsubscribeFocus, _unsubscribeOnline, _l, _m;
|
|
18
|
-
import { O as OVERLAY_LAYER_INDEX, c as createLucideIcon$1, d as usePortalContainer, a as cn$1, e as OVERLAY_LAYER, s as stopEscapePropagation, P as Presence,
|
|
19
|
-
import {
|
|
18
|
+
import { O as OVERLAY_LAYER_INDEX, c as createLucideIcon$1, d as usePortalContainer, a as cn$1, e as OVERLAY_LAYER, s as stopEscapePropagation, f as useControllableState, g as useId$1, P as Presence, h as Primitive, i as composeEventHandlers, j as useDismissableLayerSurface, k as useComposedRefs$1, l as Portal$1, m as createContextScope, n as createSlot, D as DismissableLayer, o as useLayoutEffect2, p as useCallbackRef, u as ungzip_1, q as PortalContainerProvider, r as registerThree } from "./three-B228j4M6.js";
|
|
19
|
+
import { L as toast, M as trimLogBackupPayload, O as createSafeLogBackup, P as getLogBackupSessionId, N as NetworkCollector, C as ConsoleCollector, W as WebSocketCollector, Q as createIndexedDbLogBackup, e as buildJiraCreateFields, R as Popover, T as PopoverTrigger, U as Input, X as PopoverContent, Y as Label, Z as Select, _ as SelectTrigger, $ as SelectValue, a0 as SelectContent, a1 as SelectItem, a2 as JIRA_ISSUE_TYPE_VALUE_KEY, a3 as getJiraMetadata, a4 as buildJiraIssueFields, a5 as getJiraIssueTypeLabel, a6 as Button, a7 as Root2$2, a8 as Trigger$2, a9 as ChevronDown, aa as Portal, ab as Content2$1, ac as Check, ad as X$1, ae as DatePicker, f as buildNotionCreateFields, af as getNotionPageMetadata, ag as buildNotionFieldViews, b as captureWithModernScreenshot, p as pristineFetch, d as directUploadToSignedUrl, ah as DirectUploadError, a as uploadSignedMediaWithApi, v as sanitizeString, ai as getRegisteredUploadId, h as buildGuestOwnerQuery, z as createIssueUploadQueues, G as loadTusClient, H as createIndexedDbPendingUploadStore, K as createMediaUploadApi, J as ATTACHMENT_UPLOAD_DB_NAME, V as VIDEO_UPLOAD_DB_NAME, aj as getSnapshot, ak as subscribe$1, k as devLogger, y as getCurrentPageUrl, al as ChevronRight, am as ReactRemoveScroll, an as hideOthers, ao as useFocusGuards, ap as FocusScope, aq as createShadowDismissRoot, ar as getExposedJiraFields, as as isJiraFieldExposed, at as normalizeExposedJiraFields, c as captureViewportWithElementCrop, B as preloadModernScreenshot, g as getElementPosition, u as uploadScreenshotDataUrls, l as filterExcludeServiceRelatedLogs, m as filterExcludeServiceRelatedConsoleLogs, s as selectNetworkLogsForSubmit, n as compactNetworkLogsForTransport, o as CONSOLE_LOG_SUBMIT_LIMIT, q as buildExternalUserPayload, w as collectAttachmentUploads, x as hasReplayUpload, r as shrinkNetworkLogsToFit, t as measureJsonBytes, j as buildIssueIntegrationsPayload, D as enqueueIssueUploads, E as normalizeUploadMimeType, A as SessionReplayCaptureController, au as resolveJiraIssueTypeId, av as pickJiraIssueTypeFields, aw as switchJiraIssueType, ax as getPrimaryJiraMapping, ay as createCollection, az as useDirection, aA as useShadowOutsideDismiss, aB as getPrimaryNotionMapping, aC as buttonVariants, aD as TEST_ATTR_KEYS, aE as jaccard, aF as textSimilarity, aG as collectHeadings, aH as buildElementLocator, aI as normalizeForCompare, aJ as CONTAINER_SELECTOR, aK as safeRole, aL as safeAccessibleName, aM as sameDigitGroups, aN as labelSimilarityKeepingDigits, aO as landmarkRole, aP as findElementBySelector, aQ as findElementByXPath, S as ScreenRecordingController, i as composeIssueFilterGroups, aR as OnboardingProvider, aS as useOnboardingTarget, aT as useOnboardingFlow, aU as PopoverAnchor } from "./externalUserPayload-DWcXyz2U.js";
|
|
20
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
20
21
|
import * as React from "react";
|
|
21
22
|
import { useRef, useState, useEffect, useId, useLayoutEffect, useCallback, forwardRef, createElement, createContext, useContext, Component, Suspense, useInsertionEffect, useMemo, Children, isValidElement, Fragment as Fragment$1, useSyncExternalStore, useDeferredValue } from "react";
|
|
22
|
-
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
23
23
|
import { createRoot } from "react-dom/client";
|
|
24
24
|
import { createPortal } from "react-dom";
|
|
25
|
-
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-CT7e9xbU.js";
|
|
26
|
+
import { g as getDefaultExportFromCjs } from "./_commonjsHelpers-DWwsNxpa.js";
|
|
27
|
+
const ISSUE_STICKER_REPORT_FORM_CLASS = "issue-sticker-report-form";
|
|
28
|
+
function summarizeVideoUploads(states) {
|
|
29
|
+
if (states.length === 0) return void 0;
|
|
30
|
+
const remaining = states.filter((state) => state.status !== "failed");
|
|
31
|
+
const current = states.find((state) => state.status === "uploading");
|
|
32
|
+
const percent2 = current && current.bytesTotal > 0 ? Math.floor(current.bytesSent / current.bytesTotal * 100) : 0;
|
|
33
|
+
return { percent: percent2, count: remaining.length, failed: remaining.length === 0 };
|
|
34
|
+
}
|
|
35
|
+
const VIDEO_UPLOAD_COPY = {
|
|
36
|
+
created: "이슈가 생성되었습니다. 영상 업로드가 끝나면 이슈에 첨부됩니다.",
|
|
37
|
+
resumed: (count) => `업로드하지 못한 영상 ${count}개를 이어서 업로드합니다.`
|
|
38
|
+
};
|
|
39
|
+
function visibleKinds(kinds) {
|
|
40
|
+
const video = kinds.includes("video");
|
|
41
|
+
const replay = kinds.includes("replay");
|
|
42
|
+
if (video && replay) return "both";
|
|
43
|
+
if (video) return "video";
|
|
44
|
+
return replay ? "replay" : null;
|
|
45
|
+
}
|
|
46
|
+
const ISSUE_UPLOAD_COPY = {
|
|
47
|
+
failedMessage: "네트워크 연결을 확인한 뒤 다시 시도해주세요.",
|
|
48
|
+
retry: "다시 시도",
|
|
49
|
+
failedTitle: {
|
|
50
|
+
video: "영상 업로드 실패",
|
|
51
|
+
replay: "세션 리플레이 업로드 실패",
|
|
52
|
+
both: "영상·세션 리플레이 업로드 실패"
|
|
53
|
+
},
|
|
54
|
+
aborted: {
|
|
55
|
+
video: "영상을 업로드하지 못했습니다.",
|
|
56
|
+
replay: "세션 리플레이를 업로드하지 못했습니다.",
|
|
57
|
+
both: "영상과 세션 리플레이를 업로드하지 못했습니다."
|
|
58
|
+
},
|
|
59
|
+
/** 완료는 영상이 있을 때만 알린다. 리플레이만 붙은 경우의 문구는 없다. */
|
|
60
|
+
attached: {
|
|
61
|
+
video: "영상이 이슈에 첨부되었습니다.",
|
|
62
|
+
both: "영상과 세션 리플레이가 이슈에 첨부되었습니다."
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function createIssueUploadToaster() {
|
|
66
|
+
const failureToastIds = /* @__PURE__ */ new Map();
|
|
67
|
+
return {
|
|
68
|
+
show(notice, retry) {
|
|
69
|
+
const previous2 = failureToastIds.get(notice.issueId);
|
|
70
|
+
if (previous2 !== void 0) {
|
|
71
|
+
toast.dismiss(previous2);
|
|
72
|
+
failureToastIds.delete(notice.issueId);
|
|
73
|
+
}
|
|
74
|
+
const failed = visibleKinds(notice.failed);
|
|
75
|
+
if (failed) {
|
|
76
|
+
const id2 = toast.error(ISSUE_UPLOAD_COPY.failedMessage, {
|
|
77
|
+
title: ISSUE_UPLOAD_COPY.failedTitle[failed],
|
|
78
|
+
duration: 0,
|
|
79
|
+
action: {
|
|
80
|
+
label: ISSUE_UPLOAD_COPY.retry,
|
|
81
|
+
onClick: () => {
|
|
82
|
+
failureToastIds.delete(notice.issueId);
|
|
83
|
+
retry(notice.issueId);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
failureToastIds.set(notice.issueId, id2);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const aborted = visibleKinds(notice.aborted);
|
|
91
|
+
if (aborted) {
|
|
92
|
+
toast.error(ISSUE_UPLOAD_COPY.aborted[aborted], {
|
|
93
|
+
title: ISSUE_UPLOAD_COPY.failedTitle[aborted]
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const completed = visibleKinds(notice.completed);
|
|
98
|
+
if (completed === "video" || completed === "both") {
|
|
99
|
+
toast.success(ISSUE_UPLOAD_COPY.attached[completed]);
|
|
40
100
|
}
|
|
41
101
|
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
102
|
+
};
|
|
45
103
|
}
|
|
46
|
-
const ISSUE_STICKER_REPORT_FORM_CLASS = "issue-sticker-report-form";
|
|
47
104
|
const DEFAULT_DEBOUNCE_MS = 1e3;
|
|
48
105
|
function bindLogBackup(options) {
|
|
49
106
|
const { store, sessionId, snapshot, restoreInto } = options;
|
|
@@ -523,17 +580,105 @@ const HOST_POINTER_GUARD_EVENTS = [
|
|
|
523
580
|
"touchstart",
|
|
524
581
|
"touchend"
|
|
525
582
|
];
|
|
583
|
+
const HOST_CAPTURE_GUARD_EVENTS = [
|
|
584
|
+
"pointerdown",
|
|
585
|
+
"mousedown",
|
|
586
|
+
"click",
|
|
587
|
+
"dblclick",
|
|
588
|
+
"auxclick",
|
|
589
|
+
"contextmenu"
|
|
590
|
+
];
|
|
591
|
+
const CLICK_EVENTS = /* @__PURE__ */ new Set(["click", "dblclick", "auxclick", "contextmenu"]);
|
|
592
|
+
const ACTIVATION_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
593
|
+
"checkbox",
|
|
594
|
+
"radio",
|
|
595
|
+
"submit",
|
|
596
|
+
"reset",
|
|
597
|
+
"image",
|
|
598
|
+
"file",
|
|
599
|
+
"color",
|
|
600
|
+
"date",
|
|
601
|
+
"datetime-local",
|
|
602
|
+
"month",
|
|
603
|
+
"time",
|
|
604
|
+
"week"
|
|
605
|
+
]);
|
|
606
|
+
function hasActivationBehavior(node2) {
|
|
607
|
+
if (!(node2 instanceof Element)) return false;
|
|
608
|
+
if (node2.matches("a[href], area[href], label, summary, [popovertarget], [commandfor]")) {
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
if (node2 instanceof HTMLButtonElement) return node2.type !== "button" && node2.form !== null;
|
|
612
|
+
if (node2 instanceof HTMLInputElement) return ACTIVATION_INPUT_TYPES.has(node2.type);
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
function cloneInsideShadow(event) {
|
|
616
|
+
const init = {
|
|
617
|
+
bubbles: event.bubbles,
|
|
618
|
+
cancelable: event.cancelable,
|
|
619
|
+
composed: false,
|
|
620
|
+
view: event.view,
|
|
621
|
+
detail: event.detail,
|
|
622
|
+
screenX: event.screenX,
|
|
623
|
+
screenY: event.screenY,
|
|
624
|
+
clientX: event.clientX,
|
|
625
|
+
clientY: event.clientY,
|
|
626
|
+
movementX: event.movementX,
|
|
627
|
+
movementY: event.movementY,
|
|
628
|
+
button: event.button,
|
|
629
|
+
buttons: event.buttons,
|
|
630
|
+
relatedTarget: event.relatedTarget,
|
|
631
|
+
ctrlKey: event.ctrlKey,
|
|
632
|
+
shiftKey: event.shiftKey,
|
|
633
|
+
altKey: event.altKey,
|
|
634
|
+
metaKey: event.metaKey
|
|
635
|
+
};
|
|
636
|
+
if (typeof PointerEvent !== "undefined" && event instanceof PointerEvent) {
|
|
637
|
+
return new PointerEvent(event.type, {
|
|
638
|
+
...init,
|
|
639
|
+
pointerId: event.pointerId,
|
|
640
|
+
pointerType: event.pointerType,
|
|
641
|
+
isPrimary: event.isPrimary,
|
|
642
|
+
width: event.width,
|
|
643
|
+
height: event.height,
|
|
644
|
+
pressure: event.pressure,
|
|
645
|
+
tangentialPressure: event.tangentialPressure,
|
|
646
|
+
tiltX: event.tiltX,
|
|
647
|
+
tiltY: event.tiltY,
|
|
648
|
+
twist: event.twist
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
return new MouseEvent(event.type, init);
|
|
652
|
+
}
|
|
526
653
|
function attachHostPointerGuard(shadowRoot) {
|
|
654
|
+
const view = shadowRoot.ownerDocument.defaultView;
|
|
527
655
|
const stopLeakingToPage = (event) => {
|
|
528
656
|
event.stopPropagation();
|
|
529
657
|
};
|
|
658
|
+
const forwardInsideWidget = (event) => {
|
|
659
|
+
const path2 = event.composedPath();
|
|
660
|
+
const origin = path2[0];
|
|
661
|
+
if (!(origin instanceof Node) || origin.getRootNode() !== shadowRoot) return;
|
|
662
|
+
if (CLICK_EVENTS.has(event.type)) {
|
|
663
|
+
const insideWidget = path2.slice(0, path2.indexOf(shadowRoot));
|
|
664
|
+
if (insideWidget.some(hasActivationBehavior)) return;
|
|
665
|
+
}
|
|
666
|
+
event.stopImmediatePropagation();
|
|
667
|
+
if (!origin.dispatchEvent(cloneInsideShadow(event))) event.preventDefault();
|
|
668
|
+
};
|
|
530
669
|
HOST_POINTER_GUARD_EVENTS.forEach((type) => {
|
|
531
670
|
shadowRoot.addEventListener(type, stopLeakingToPage);
|
|
532
671
|
});
|
|
672
|
+
HOST_CAPTURE_GUARD_EVENTS.forEach((type) => {
|
|
673
|
+
view == null ? void 0 : view.addEventListener(type, forwardInsideWidget, true);
|
|
674
|
+
});
|
|
533
675
|
return () => {
|
|
534
676
|
HOST_POINTER_GUARD_EVENTS.forEach((type) => {
|
|
535
677
|
shadowRoot.removeEventListener(type, stopLeakingToPage);
|
|
536
678
|
});
|
|
679
|
+
HOST_CAPTURE_GUARD_EVENTS.forEach((type) => {
|
|
680
|
+
view == null ? void 0 : view.removeEventListener(type, forwardInsideWidget, true);
|
|
681
|
+
});
|
|
537
682
|
};
|
|
538
683
|
}
|
|
539
684
|
const HOST_INTERACTION_GUARD_EVENTS = [
|
|
@@ -551,16 +696,32 @@ const HOST_INTERACTION_GUARD_EVENTS = [
|
|
|
551
696
|
"dragend"
|
|
552
697
|
];
|
|
553
698
|
function attachHostInteractionGuard(shadowRoot) {
|
|
699
|
+
const host = shadowRoot.host;
|
|
700
|
+
const view = shadowRoot.ownerDocument.defaultView;
|
|
554
701
|
const stopLeakingToPage = (event) => {
|
|
555
702
|
event.stopPropagation();
|
|
556
703
|
};
|
|
704
|
+
const hideFocusLeavingForWidget = (event) => {
|
|
705
|
+
if (event.relatedTarget !== host) return;
|
|
706
|
+
if (event.composedPath().includes(host)) return;
|
|
707
|
+
event.stopPropagation();
|
|
708
|
+
};
|
|
709
|
+
const hideWidgetFocus = (event) => {
|
|
710
|
+
if (event.composedPath().includes(host)) event.stopImmediatePropagation();
|
|
711
|
+
};
|
|
557
712
|
HOST_INTERACTION_GUARD_EVENTS.forEach((type) => {
|
|
558
713
|
shadowRoot.addEventListener(type, stopLeakingToPage, { passive: true });
|
|
559
714
|
});
|
|
715
|
+
view == null ? void 0 : view.addEventListener("focusout", hideFocusLeavingForWidget, true);
|
|
716
|
+
view == null ? void 0 : view.addEventListener("blur", hideFocusLeavingForWidget, true);
|
|
717
|
+
view == null ? void 0 : view.addEventListener("focus", hideWidgetFocus, true);
|
|
560
718
|
return () => {
|
|
561
719
|
HOST_INTERACTION_GUARD_EVENTS.forEach((type) => {
|
|
562
720
|
shadowRoot.removeEventListener(type, stopLeakingToPage);
|
|
563
721
|
});
|
|
722
|
+
view == null ? void 0 : view.removeEventListener("focusout", hideFocusLeavingForWidget, true);
|
|
723
|
+
view == null ? void 0 : view.removeEventListener("blur", hideFocusLeavingForWidget, true);
|
|
724
|
+
view == null ? void 0 : view.removeEventListener("focus", hideWidgetFocus, true);
|
|
564
725
|
};
|
|
565
726
|
}
|
|
566
727
|
const RUNTIME_OWNER_MARKER_KEY = "__issueStickerRuntimeOwner";
|
|
@@ -1482,7 +1643,7 @@ function MultiSelect({
|
|
|
1482
1643
|
const contentRef = React.useRef(null);
|
|
1483
1644
|
const portalContainer = usePortalContainer();
|
|
1484
1645
|
React.useEffect(() => {
|
|
1485
|
-
var _a, _b2;
|
|
1646
|
+
var _a, _b2, _c2, _d2;
|
|
1486
1647
|
if (!open) {
|
|
1487
1648
|
return;
|
|
1488
1649
|
}
|
|
@@ -1493,8 +1654,12 @@ function MultiSelect({
|
|
|
1493
1654
|
}
|
|
1494
1655
|
setOpen(false);
|
|
1495
1656
|
};
|
|
1496
|
-
|
|
1497
|
-
|
|
1657
|
+
const scopes = /* @__PURE__ */ new Set([
|
|
1658
|
+
ownerDocument,
|
|
1659
|
+
((_c2 = contentRef.current) == null ? void 0 : _c2.getRootNode()) ?? ((_d2 = triggerRef.current) == null ? void 0 : _d2.getRootNode()) ?? ownerDocument
|
|
1660
|
+
]);
|
|
1661
|
+
scopes.forEach((scope) => scope.addEventListener("click", closeOnOutsideClick, true));
|
|
1662
|
+
return () => scopes.forEach((scope) => scope.removeEventListener("click", closeOnOutsideClick, true));
|
|
1498
1663
|
}, [open]);
|
|
1499
1664
|
const emitChange = (next) => {
|
|
1500
1665
|
onValueChange == null ? void 0 : onValueChange(next);
|
|
@@ -5127,6 +5292,612 @@ class WebPlatform {
|
|
|
5127
5292
|
this.eventBus = eventBus;
|
|
5128
5293
|
}
|
|
5129
5294
|
}
|
|
5295
|
+
function isHttpStatusError(error) {
|
|
5296
|
+
return typeof error === "object" && error !== null && typeof error.status === "number";
|
|
5297
|
+
}
|
|
5298
|
+
const MAX_RETRIES = 3;
|
|
5299
|
+
const MAX_BACKOFF_MS = 3e4;
|
|
5300
|
+
const MAX_RETRY_AFTER_MS = 6e4;
|
|
5301
|
+
function parseRetryAfterMs(value, now2 = Date.now()) {
|
|
5302
|
+
const trimmed = value == null ? void 0 : value.trim();
|
|
5303
|
+
if (!trimmed) return void 0;
|
|
5304
|
+
if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
|
|
5305
|
+
const date = Date.parse(trimmed);
|
|
5306
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - now2);
|
|
5307
|
+
}
|
|
5308
|
+
function retryAfterMsOf(response) {
|
|
5309
|
+
var _a;
|
|
5310
|
+
return parseRetryAfterMs((_a = response.headers) == null ? void 0 : _a.get("Retry-After"));
|
|
5311
|
+
}
|
|
5312
|
+
function jitteredBackoffMs(failureCount, capMs = MAX_BACKOFF_MS) {
|
|
5313
|
+
return Math.random() * Math.min(capMs, 1e3 * 2 ** failureCount);
|
|
5314
|
+
}
|
|
5315
|
+
function statusOf(error) {
|
|
5316
|
+
return isHttpStatusError(error) ? error.status : 0;
|
|
5317
|
+
}
|
|
5318
|
+
function retryAfterOf(error) {
|
|
5319
|
+
return isHttpStatusError(error) ? error.retryAfterMs : void 0;
|
|
5320
|
+
}
|
|
5321
|
+
function queryRetry(failureCount, error) {
|
|
5322
|
+
const status = statusOf(error);
|
|
5323
|
+
if (status === 429) {
|
|
5324
|
+
const retryAfterMs = retryAfterOf(error);
|
|
5325
|
+
return failureCount < 1 && retryAfterMs !== void 0 && retryAfterMs <= MAX_RETRY_AFTER_MS;
|
|
5326
|
+
}
|
|
5327
|
+
if (status >= 400 && status < 500 && status !== 408) return false;
|
|
5328
|
+
return failureCount < MAX_RETRIES;
|
|
5329
|
+
}
|
|
5330
|
+
function queryRetryDelay(failureCount, error) {
|
|
5331
|
+
const retryAfterMs = retryAfterOf(error);
|
|
5332
|
+
return retryAfterMs !== void 0 ? Math.min(retryAfterMs, MAX_RETRY_AFTER_MS) : jitteredBackoffMs(failureCount);
|
|
5333
|
+
}
|
|
5334
|
+
function readApiBaseUrlFromEnv() {
|
|
5335
|
+
if (typeof process !== "undefined" && process.env && Object.prototype.hasOwnProperty.call(process.env, "VITE_API_BASE_URL")) {
|
|
5336
|
+
const processValue = process.env.VITE_API_BASE_URL;
|
|
5337
|
+
if (typeof processValue === "string") {
|
|
5338
|
+
const trimmed = processValue.trim();
|
|
5339
|
+
return trimmed.length > 0 && trimmed !== "undefined" ? trimmed : void 0;
|
|
5340
|
+
}
|
|
5341
|
+
}
|
|
5342
|
+
const viteValue = "https://api.issuesticker.com";
|
|
5343
|
+
{
|
|
5344
|
+
const trimmed = viteValue.trim();
|
|
5345
|
+
return trimmed.length > 0 && trimmed !== "undefined" ? trimmed : void 0;
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
let tokenMemoryCache = null;
|
|
5349
|
+
let apiKeyCache = null;
|
|
5350
|
+
let sdkMode = null;
|
|
5351
|
+
let memberTokenProvider = null;
|
|
5352
|
+
function normalizeToken(token) {
|
|
5353
|
+
const trimmed = token.trim();
|
|
5354
|
+
if (trimmed.toLowerCase().startsWith("bearer ")) {
|
|
5355
|
+
return trimmed.slice(7).trim();
|
|
5356
|
+
}
|
|
5357
|
+
return trimmed;
|
|
5358
|
+
}
|
|
5359
|
+
function createMemberAuthRequiredError(message = "멤버 로그인이 필요합니다.") {
|
|
5360
|
+
return new ApiError(message, 401, {
|
|
5361
|
+
success: false,
|
|
5362
|
+
error: {
|
|
5363
|
+
code: "MEMBER_AUTH_REQUIRED",
|
|
5364
|
+
message
|
|
5365
|
+
}
|
|
5366
|
+
});
|
|
5367
|
+
}
|
|
5368
|
+
async function resolveAuthorizationHeader(options) {
|
|
5369
|
+
if (sdkMode === "public" || sdkMode === null) {
|
|
5370
|
+
if (apiKeyCache) {
|
|
5371
|
+
return `ApiKey ${apiKeyCache}`;
|
|
5372
|
+
}
|
|
5373
|
+
return void 0;
|
|
5374
|
+
}
|
|
5375
|
+
if (sdkMode === "member" && memberTokenProvider) {
|
|
5376
|
+
const token2 = await memberTokenProvider({
|
|
5377
|
+
forceRefresh: options == null ? void 0 : options.forceRefreshMemberToken,
|
|
5378
|
+
reason: (options == null ? void 0 : options.memberRefreshReason) || "missing"
|
|
5379
|
+
});
|
|
5380
|
+
if (!token2) {
|
|
5381
|
+
throw createMemberAuthRequiredError();
|
|
5382
|
+
}
|
|
5383
|
+
return `Bearer ${token2}`;
|
|
5384
|
+
}
|
|
5385
|
+
const token = tokenMemoryCache ? normalizeToken(tokenMemoryCache) : null;
|
|
5386
|
+
if (token) {
|
|
5387
|
+
return `Bearer ${token}`;
|
|
5388
|
+
}
|
|
5389
|
+
return void 0;
|
|
5390
|
+
}
|
|
5391
|
+
const isDemoMode = false;
|
|
5392
|
+
function getApiBaseUrl() {
|
|
5393
|
+
const baseUrl = readApiBaseUrlFromEnv();
|
|
5394
|
+
if (!baseUrl) {
|
|
5395
|
+
throw new ApiError(
|
|
5396
|
+
"API 서버 주소(VITE_API_BASE_URL)가 설정되지 않았습니다. SDK 빌드/환경을 확인해주세요.",
|
|
5397
|
+
0
|
|
5398
|
+
);
|
|
5399
|
+
}
|
|
5400
|
+
if (!/^https?:\/\//.test(baseUrl)) {
|
|
5401
|
+
throw new ApiError(`API 서버 주소(VITE_API_BASE_URL)가 올바르지 않습니다: ${baseUrl}`, 0);
|
|
5402
|
+
}
|
|
5403
|
+
return baseUrl.replace(/\/+$/, "");
|
|
5404
|
+
}
|
|
5405
|
+
function setApiKey(key) {
|
|
5406
|
+
apiKeyCache = key;
|
|
5407
|
+
}
|
|
5408
|
+
function setSdkMode(mode) {
|
|
5409
|
+
sdkMode = mode;
|
|
5410
|
+
}
|
|
5411
|
+
function getSdkMode() {
|
|
5412
|
+
return sdkMode;
|
|
5413
|
+
}
|
|
5414
|
+
function setMemberTokenProvider(provider) {
|
|
5415
|
+
memberTokenProvider = provider;
|
|
5416
|
+
}
|
|
5417
|
+
function assertRelativeApiEndpoint(endpoint) {
|
|
5418
|
+
if (!endpoint.startsWith("/") || endpoint.startsWith("//")) {
|
|
5419
|
+
throw new ApiError(`API endpoint는 백엔드 상대 경로여야 합니다: ${endpoint}`, 0);
|
|
5420
|
+
}
|
|
5421
|
+
}
|
|
5422
|
+
function buildApiUrl(endpoint) {
|
|
5423
|
+
assertRelativeApiEndpoint(endpoint);
|
|
5424
|
+
return `${getApiBaseUrl()}${endpoint}`;
|
|
5425
|
+
}
|
|
5426
|
+
async function saveToken(token) {
|
|
5427
|
+
const normalizedToken = normalizeToken(token);
|
|
5428
|
+
tokenMemoryCache = normalizedToken;
|
|
5429
|
+
}
|
|
5430
|
+
async function clearToken() {
|
|
5431
|
+
tokenMemoryCache = null;
|
|
5432
|
+
}
|
|
5433
|
+
class ApiError extends Error {
|
|
5434
|
+
constructor(message, status, data, retryAfterMs) {
|
|
5435
|
+
super(message);
|
|
5436
|
+
this.status = status;
|
|
5437
|
+
this.data = data;
|
|
5438
|
+
this.retryAfterMs = retryAfterMs;
|
|
5439
|
+
this.name = "ApiError";
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
function extractErrorMessage(error) {
|
|
5443
|
+
if (!error) return void 0;
|
|
5444
|
+
if (typeof error === "string") return error;
|
|
5445
|
+
return error.message || error.code || JSON.stringify(error);
|
|
5446
|
+
}
|
|
5447
|
+
async function requestResponse(endpoint, options = {}) {
|
|
5448
|
+
const { body, skipAuth = false, headers: customHeaders, ...rest } = options;
|
|
5449
|
+
const headers = {
|
|
5450
|
+
"Content-Type": "application/json",
|
|
5451
|
+
"x-client-info": "issue-sticker-sdk",
|
|
5452
|
+
...customHeaders || {}
|
|
5453
|
+
};
|
|
5454
|
+
if (!skipAuth) {
|
|
5455
|
+
const authHeader = await resolveAuthorizationHeader();
|
|
5456
|
+
if (authHeader) {
|
|
5457
|
+
headers["Authorization"] = authHeader;
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
const url = buildApiUrl(endpoint);
|
|
5461
|
+
const execute = (nextHeaders) => pristineFetch(url, {
|
|
5462
|
+
...rest,
|
|
5463
|
+
headers: nextHeaders,
|
|
5464
|
+
body: body ? JSON.stringify(body) : void 0
|
|
5465
|
+
});
|
|
5466
|
+
let response = await execute(headers);
|
|
5467
|
+
let retriedMemberAuth = false;
|
|
5468
|
+
if (!skipAuth && response.status === 401 && sdkMode === "member" && memberTokenProvider) {
|
|
5469
|
+
const retryHeaders = { ...headers };
|
|
5470
|
+
try {
|
|
5471
|
+
const authHeader = await resolveAuthorizationHeader({
|
|
5472
|
+
forceRefreshMemberToken: true,
|
|
5473
|
+
memberRefreshReason: "unauthorized"
|
|
5474
|
+
});
|
|
5475
|
+
if (authHeader) {
|
|
5476
|
+
retryHeaders.Authorization = authHeader;
|
|
5477
|
+
retriedMemberAuth = true;
|
|
5478
|
+
response = await execute(retryHeaders);
|
|
5479
|
+
}
|
|
5480
|
+
} catch {
|
|
5481
|
+
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5482
|
+
success: false,
|
|
5483
|
+
error: {
|
|
5484
|
+
code: "SESSION_EXPIRED",
|
|
5485
|
+
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5486
|
+
}
|
|
5487
|
+
});
|
|
5488
|
+
}
|
|
5489
|
+
}
|
|
5490
|
+
if (retriedMemberAuth && response.status === 401) {
|
|
5491
|
+
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5492
|
+
success: false,
|
|
5493
|
+
error: {
|
|
5494
|
+
code: "SESSION_EXPIRED",
|
|
5495
|
+
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5496
|
+
}
|
|
5497
|
+
});
|
|
5498
|
+
}
|
|
5499
|
+
if (response.status === 204) {
|
|
5500
|
+
return { success: true };
|
|
5501
|
+
}
|
|
5502
|
+
const json = await response.json();
|
|
5503
|
+
if (!response.ok || !json.success) {
|
|
5504
|
+
throw new ApiError(
|
|
5505
|
+
extractErrorMessage(json.error) || json.message || `요청 실패: ${response.status}`,
|
|
5506
|
+
response.status,
|
|
5507
|
+
json,
|
|
5508
|
+
retryAfterMsOf(response)
|
|
5509
|
+
);
|
|
5510
|
+
}
|
|
5511
|
+
return json;
|
|
5512
|
+
}
|
|
5513
|
+
async function request(endpoint, options = {}) {
|
|
5514
|
+
const json = await requestResponse(endpoint, options);
|
|
5515
|
+
return json.data;
|
|
5516
|
+
}
|
|
5517
|
+
async function uploadRequest(endpoint, formData, skipAuth = false) {
|
|
5518
|
+
const headers = {
|
|
5519
|
+
"x-client-info": "issue-sticker-sdk"
|
|
5520
|
+
};
|
|
5521
|
+
if (!skipAuth) {
|
|
5522
|
+
const authHeader = await resolveAuthorizationHeader();
|
|
5523
|
+
if (authHeader) {
|
|
5524
|
+
headers["Authorization"] = authHeader;
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5527
|
+
const url = buildApiUrl(endpoint);
|
|
5528
|
+
const execute = (nextHeaders) => pristineFetch(url, {
|
|
5529
|
+
method: "POST",
|
|
5530
|
+
headers: nextHeaders,
|
|
5531
|
+
body: formData
|
|
5532
|
+
});
|
|
5533
|
+
let response = await execute(headers);
|
|
5534
|
+
let retriedMemberAuth = false;
|
|
5535
|
+
if (!skipAuth && response.status === 401 && sdkMode === "member" && memberTokenProvider) {
|
|
5536
|
+
const retryHeaders = { ...headers };
|
|
5537
|
+
try {
|
|
5538
|
+
const authHeader = await resolveAuthorizationHeader({
|
|
5539
|
+
forceRefreshMemberToken: true,
|
|
5540
|
+
memberRefreshReason: "unauthorized"
|
|
5541
|
+
});
|
|
5542
|
+
if (authHeader) {
|
|
5543
|
+
retryHeaders.Authorization = authHeader;
|
|
5544
|
+
retriedMemberAuth = true;
|
|
5545
|
+
response = await execute(retryHeaders);
|
|
5546
|
+
}
|
|
5547
|
+
} catch {
|
|
5548
|
+
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5549
|
+
success: false,
|
|
5550
|
+
error: {
|
|
5551
|
+
code: "SESSION_EXPIRED",
|
|
5552
|
+
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5553
|
+
}
|
|
5554
|
+
});
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
if (retriedMemberAuth && response.status === 401) {
|
|
5558
|
+
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5559
|
+
success: false,
|
|
5560
|
+
error: {
|
|
5561
|
+
code: "SESSION_EXPIRED",
|
|
5562
|
+
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5563
|
+
}
|
|
5564
|
+
});
|
|
5565
|
+
}
|
|
5566
|
+
const json = await response.json();
|
|
5567
|
+
if (!response.ok || !json.success) {
|
|
5568
|
+
throw new ApiError(
|
|
5569
|
+
extractErrorMessage(json.error) || json.message || `업로드 실패: ${response.status}`,
|
|
5570
|
+
response.status,
|
|
5571
|
+
json,
|
|
5572
|
+
retryAfterMsOf(response)
|
|
5573
|
+
);
|
|
5574
|
+
}
|
|
5575
|
+
return json.data;
|
|
5576
|
+
}
|
|
5577
|
+
async function directUpload(signedUrl, file, contentType) {
|
|
5578
|
+
try {
|
|
5579
|
+
await directUploadToSignedUrl(signedUrl, file, contentType);
|
|
5580
|
+
} catch (error) {
|
|
5581
|
+
if (error instanceof ApiError) {
|
|
5582
|
+
throw error;
|
|
5583
|
+
}
|
|
5584
|
+
if (error instanceof DirectUploadError) {
|
|
5585
|
+
throw new ApiError(error.message, error.status, error.data);
|
|
5586
|
+
}
|
|
5587
|
+
throw new ApiError(error instanceof Error ? error.message : "스토리지 업로드 실패", 0, error);
|
|
5588
|
+
}
|
|
5589
|
+
}
|
|
5590
|
+
const apiClient = {
|
|
5591
|
+
get(endpoint, options) {
|
|
5592
|
+
return request(endpoint, { ...options, method: "GET" });
|
|
5593
|
+
},
|
|
5594
|
+
getResponse(endpoint, options) {
|
|
5595
|
+
return requestResponse(endpoint, { ...options, method: "GET" });
|
|
5596
|
+
},
|
|
5597
|
+
post(endpoint, body, options) {
|
|
5598
|
+
return request(endpoint, { ...options, method: "POST", body });
|
|
5599
|
+
},
|
|
5600
|
+
put(endpoint, body, options) {
|
|
5601
|
+
return request(endpoint, { ...options, method: "PUT", body });
|
|
5602
|
+
},
|
|
5603
|
+
delete(endpoint, options) {
|
|
5604
|
+
return request(endpoint, { ...options, method: "DELETE" });
|
|
5605
|
+
},
|
|
5606
|
+
upload(endpoint, formData, skipAuth) {
|
|
5607
|
+
return uploadRequest(endpoint, formData, skipAuth);
|
|
5608
|
+
}
|
|
5609
|
+
};
|
|
5610
|
+
const queryClient = new QueryClient({
|
|
5611
|
+
defaultOptions: {
|
|
5612
|
+
queries: {
|
|
5613
|
+
staleTime: 5 * 60 * 1e3,
|
|
5614
|
+
// 5분
|
|
5615
|
+
gcTime: 10 * 60 * 1e3,
|
|
5616
|
+
// 10분 (v5에서는 cacheTime 대신 gcTime 사용)
|
|
5617
|
+
refetchOnWindowFocus: true,
|
|
5618
|
+
refetchOnReconnect: true,
|
|
5619
|
+
retry: queryRetry,
|
|
5620
|
+
retryDelay: queryRetryDelay
|
|
5621
|
+
},
|
|
5622
|
+
mutations: {
|
|
5623
|
+
retry: 0
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5626
|
+
});
|
|
5627
|
+
async function uploadSignedMedia(file, mediaType, issueId) {
|
|
5628
|
+
return uploadSignedMediaWithApi(
|
|
5629
|
+
{
|
|
5630
|
+
post: (endpoint, body) => apiClient.post(endpoint, body),
|
|
5631
|
+
directUpload
|
|
5632
|
+
},
|
|
5633
|
+
file,
|
|
5634
|
+
mediaType,
|
|
5635
|
+
{ issueId }
|
|
5636
|
+
);
|
|
5637
|
+
}
|
|
5638
|
+
function issuesEndpoint() {
|
|
5639
|
+
return "/api/sdk/issues";
|
|
5640
|
+
}
|
|
5641
|
+
function guestOwnerQuery() {
|
|
5642
|
+
var _a;
|
|
5643
|
+
const mode = getSdkMode();
|
|
5644
|
+
if (mode !== "public") return "";
|
|
5645
|
+
return buildGuestOwnerQuery(mode, (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id);
|
|
5646
|
+
}
|
|
5647
|
+
let issuesCache = null;
|
|
5648
|
+
const CACHE_DURATION_MS = 30 * 1e3;
|
|
5649
|
+
const STICKER_PAGE_SIZE = 500;
|
|
5650
|
+
const STICKER_FETCH_LIMIT = 2e3;
|
|
5651
|
+
function getFilterKey(filters) {
|
|
5652
|
+
var _a;
|
|
5653
|
+
const normalizeArray = (value) => {
|
|
5654
|
+
if (value === "all" || !value) return "all";
|
|
5655
|
+
if (Array.isArray(value)) {
|
|
5656
|
+
return value.length === 0 ? "all" : [...value].sort().join(",");
|
|
5657
|
+
}
|
|
5658
|
+
return String(value);
|
|
5659
|
+
};
|
|
5660
|
+
const normalizeRecord = (record) => {
|
|
5661
|
+
if (!record) return "";
|
|
5662
|
+
const entries = Object.entries(record).map(([k, v]) => [k, [...v].sort()]).sort(([a], [b]) => a.localeCompare(b));
|
|
5663
|
+
return JSON.stringify(entries);
|
|
5664
|
+
};
|
|
5665
|
+
return JSON.stringify({
|
|
5666
|
+
sdkMode: getSdkMode() || "public",
|
|
5667
|
+
url: normalizeArray(filters.url),
|
|
5668
|
+
projectId: filters.projectId || "all",
|
|
5669
|
+
externalUserId: filters.externalUserId || "",
|
|
5670
|
+
search: ((_a = filters.search) == null ? void 0 : _a.trim()) || "",
|
|
5671
|
+
dateFrom: filters.dateFrom || "",
|
|
5672
|
+
dateTo: filters.dateTo || "",
|
|
5673
|
+
page: filters.page ?? 0,
|
|
5674
|
+
pageSize: filters.pageSize ?? 0,
|
|
5675
|
+
custom: normalizeRecord(filters.customFieldValues),
|
|
5676
|
+
jira: normalizeRecord(filters.jiraFieldValues),
|
|
5677
|
+
notion: normalizeRecord(filters.notionFieldValues),
|
|
5678
|
+
sortOrder: filters.sortOrder || ""
|
|
5679
|
+
});
|
|
5680
|
+
}
|
|
5681
|
+
function invalidateIssuesCache() {
|
|
5682
|
+
issuesCache = null;
|
|
5683
|
+
}
|
|
5684
|
+
function recordToFilterArray(record, keyFieldName) {
|
|
5685
|
+
if (!record) return null;
|
|
5686
|
+
const entries = Object.entries(record).filter(([, values]) => values.length > 0);
|
|
5687
|
+
if (entries.length === 0) return null;
|
|
5688
|
+
return entries.map(
|
|
5689
|
+
([key, values]) => ({ [keyFieldName]: key, values })
|
|
5690
|
+
);
|
|
5691
|
+
}
|
|
5692
|
+
function buildFilterQueryParams(filters) {
|
|
5693
|
+
var _a;
|
|
5694
|
+
const params = new URLSearchParams();
|
|
5695
|
+
if (filters.projectId) {
|
|
5696
|
+
params.set("project_id", filters.projectId);
|
|
5697
|
+
}
|
|
5698
|
+
if (filters.url && filters.url !== "all") {
|
|
5699
|
+
if (Array.isArray(filters.url) && filters.url.length > 0) {
|
|
5700
|
+
params.set("url", filters.url.join(","));
|
|
5701
|
+
} else if (typeof filters.url === "string") {
|
|
5702
|
+
params.set("url", filters.url);
|
|
5703
|
+
}
|
|
5704
|
+
}
|
|
5705
|
+
const search2 = (_a = filters.search) == null ? void 0 : _a.trim();
|
|
5706
|
+
if (search2) {
|
|
5707
|
+
params.set("search", search2);
|
|
5708
|
+
}
|
|
5709
|
+
if (filters.dateFrom) {
|
|
5710
|
+
params.set("date_from", filters.dateFrom);
|
|
5711
|
+
}
|
|
5712
|
+
if (filters.dateTo) {
|
|
5713
|
+
params.set("date_to", filters.dateTo);
|
|
5714
|
+
}
|
|
5715
|
+
const customArr = recordToFilterArray(filters.customFieldValues, "fieldDefinitionId");
|
|
5716
|
+
if (customArr) {
|
|
5717
|
+
params.set("custom_field_filters", JSON.stringify(customArr));
|
|
5718
|
+
}
|
|
5719
|
+
const jiraArr = recordToFilterArray(filters.jiraFieldValues, "fieldName");
|
|
5720
|
+
if (jiraArr) {
|
|
5721
|
+
params.set("jira_field_filters", JSON.stringify(jiraArr));
|
|
5722
|
+
}
|
|
5723
|
+
const notionArr = recordToFilterArray(filters.notionFieldValues, "fieldName");
|
|
5724
|
+
if (notionArr) {
|
|
5725
|
+
params.set("notion_field_filters", JSON.stringify(notionArr));
|
|
5726
|
+
}
|
|
5727
|
+
if (filters.externalUserId) {
|
|
5728
|
+
params.set("external_user_id", filters.externalUserId);
|
|
5729
|
+
}
|
|
5730
|
+
if (typeof filters.page === "number" && filters.page > 0) {
|
|
5731
|
+
params.set("page", String(filters.page));
|
|
5732
|
+
}
|
|
5733
|
+
if (typeof filters.pageSize === "number" && filters.pageSize > 0) {
|
|
5734
|
+
params.set("page_size", String(filters.pageSize));
|
|
5735
|
+
}
|
|
5736
|
+
if (filters.sortOrder) {
|
|
5737
|
+
params.set("sort_order", filters.sortOrder);
|
|
5738
|
+
}
|
|
5739
|
+
const queryString = params.toString();
|
|
5740
|
+
return queryString ? `?${queryString}` : "";
|
|
5741
|
+
}
|
|
5742
|
+
const issueService = {
|
|
5743
|
+
async createIssue(issueData) {
|
|
5744
|
+
const sanitizedData = sanitizeString(issueData);
|
|
5745
|
+
const screenshotUploadIds = (sanitizedData.screenshot || []).map((url) => getRegisteredUploadId(url, "screenshot")).filter((id2) => typeof id2 === "string" && id2.length > 0);
|
|
5746
|
+
const videoUploadId = sanitizedData.video ? getRegisteredUploadId(sanitizedData.video, "video") : void 0;
|
|
5747
|
+
if (screenshotUploadIds.length > 0) {
|
|
5748
|
+
sanitizedData.screenshot_upload_ids = screenshotUploadIds;
|
|
5749
|
+
}
|
|
5750
|
+
if (videoUploadId) {
|
|
5751
|
+
sanitizedData.video_upload_id = videoUploadId;
|
|
5752
|
+
}
|
|
5753
|
+
const issue = await apiClient.post(issuesEndpoint(), sanitizedData);
|
|
5754
|
+
invalidateIssuesCache();
|
|
5755
|
+
return issue;
|
|
5756
|
+
},
|
|
5757
|
+
async getIssues(filters = {}, options = {}) {
|
|
5758
|
+
if (!filters.projectId) {
|
|
5759
|
+
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
5760
|
+
}
|
|
5761
|
+
const filterKey = getFilterKey(filters);
|
|
5762
|
+
const now2 = Date.now();
|
|
5763
|
+
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
5764
|
+
return issuesCache.data;
|
|
5765
|
+
}
|
|
5766
|
+
const queryParams = buildFilterQueryParams(filters);
|
|
5767
|
+
const { items: issues = [] } = await apiClient.get(
|
|
5768
|
+
`${issuesEndpoint()}${queryParams}`
|
|
5769
|
+
);
|
|
5770
|
+
issuesCache = {
|
|
5771
|
+
data: issues,
|
|
5772
|
+
timestamp: now2,
|
|
5773
|
+
filterKey
|
|
5774
|
+
};
|
|
5775
|
+
return issues;
|
|
5776
|
+
},
|
|
5777
|
+
async getIssueStickers(filters = {}, options = {}) {
|
|
5778
|
+
var _a, _b2;
|
|
5779
|
+
if (!filters.projectId) {
|
|
5780
|
+
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
5781
|
+
}
|
|
5782
|
+
const filterKey = `${getFilterKey(filters)}:stickers`;
|
|
5783
|
+
const now2 = Date.now();
|
|
5784
|
+
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
5785
|
+
return issuesCache.data;
|
|
5786
|
+
}
|
|
5787
|
+
const issues = [];
|
|
5788
|
+
let page = 1;
|
|
5789
|
+
let hasMore = true;
|
|
5790
|
+
while (hasMore && issues.length <= STICKER_FETCH_LIMIT) {
|
|
5791
|
+
const response = await apiClient.getResponse(
|
|
5792
|
+
`${issuesEndpoint()}/stickers${buildFilterQueryParams({
|
|
5793
|
+
...filters,
|
|
5794
|
+
page,
|
|
5795
|
+
pageSize: STICKER_PAGE_SIZE
|
|
5796
|
+
})}`
|
|
5797
|
+
);
|
|
5798
|
+
const pageItems = ((_a = response.data) == null ? void 0 : _a.items) ?? [];
|
|
5799
|
+
issues.push(...pageItems);
|
|
5800
|
+
hasMore = Boolean((_b2 = response.data) == null ? void 0 : _b2.hasMore) && pageItems.length > 0;
|
|
5801
|
+
page += 1;
|
|
5802
|
+
}
|
|
5803
|
+
issuesCache = {
|
|
5804
|
+
data: issues,
|
|
5805
|
+
timestamp: now2,
|
|
5806
|
+
filterKey
|
|
5807
|
+
};
|
|
5808
|
+
return issues;
|
|
5809
|
+
},
|
|
5810
|
+
invalidateCache() {
|
|
5811
|
+
invalidateIssuesCache();
|
|
5812
|
+
},
|
|
5813
|
+
// 계약 기준: 백엔드 GET /api/sdk/issues/:id 는 back#101부터 읽기-시점-스크럽된
|
|
5814
|
+
// llm_prompt 를 상세 응답에 포함한다(목록 응답에는 없음) — 스코프를 이 반환 타입에만 한정한다.
|
|
5815
|
+
async getIssue(id2) {
|
|
5816
|
+
return apiClient.get(
|
|
5817
|
+
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`
|
|
5818
|
+
);
|
|
5819
|
+
},
|
|
5820
|
+
async updateIssue(id2, updates) {
|
|
5821
|
+
const sanitizedUpdates = sanitizeString(updates);
|
|
5822
|
+
const issue = await apiClient.put(
|
|
5823
|
+
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`,
|
|
5824
|
+
sanitizedUpdates
|
|
5825
|
+
);
|
|
5826
|
+
invalidateIssuesCache();
|
|
5827
|
+
return issue;
|
|
5828
|
+
},
|
|
5829
|
+
/**
|
|
5830
|
+
* 재생성. 스펙상 세 채널 모두에서 되고 역할과 무관하다 — 검사는 역할이 아니라
|
|
5831
|
+
* 그 이슈에 접근할 수 있는지다(백엔드가 판정한다).
|
|
5832
|
+
*
|
|
5833
|
+
* 응답으로 갱신된 이슈가 오지만 상태는 다시 pending 이다. 호출부는 응답을
|
|
5834
|
+
* 그대로 쓰지 말고 폴링으로 이어받아야 한다.
|
|
5835
|
+
*/
|
|
5836
|
+
async regenerateIssue(id2) {
|
|
5837
|
+
const issue = await apiClient.post(
|
|
5838
|
+
`${issuesEndpoint()}/${encodeURIComponent(id2)}/regenerate${guestOwnerQuery()}`,
|
|
5839
|
+
{}
|
|
5840
|
+
);
|
|
5841
|
+
invalidateIssuesCache();
|
|
5842
|
+
return issue;
|
|
5843
|
+
},
|
|
5844
|
+
async deleteIssue(id2, options) {
|
|
5845
|
+
const endpoint = `${issuesEndpoint()}/${id2}${guestOwnerQuery()}`;
|
|
5846
|
+
if (options == null ? void 0 : options.deleteExternal) {
|
|
5847
|
+
await apiClient.delete(endpoint, {
|
|
5848
|
+
body: { deleteExternal: true }
|
|
5849
|
+
});
|
|
5850
|
+
} else {
|
|
5851
|
+
await apiClient.delete(endpoint);
|
|
5852
|
+
}
|
|
5853
|
+
invalidateIssuesCache();
|
|
5854
|
+
}
|
|
5855
|
+
};
|
|
5856
|
+
function invalidateIssueQueries(issueId) {
|
|
5857
|
+
issueService.invalidateCache();
|
|
5858
|
+
queryClient.invalidateQueries({ queryKey: ["contentIssues"] });
|
|
5859
|
+
queryClient.invalidateQueries({ queryKey: ["issue", issueId] });
|
|
5860
|
+
}
|
|
5861
|
+
function notifyIssueUpdated(issueId) {
|
|
5862
|
+
SDKManager.getInstance().eventBus.emit("issue:updated", issueId);
|
|
5863
|
+
}
|
|
5864
|
+
function applyIssueMutationEffects(issueId) {
|
|
5865
|
+
invalidateIssueQueries(issueId);
|
|
5866
|
+
notifyIssueUpdated(issueId);
|
|
5867
|
+
}
|
|
5868
|
+
let queues = null;
|
|
5869
|
+
const toaster = createIssueUploadToaster();
|
|
5870
|
+
function getQueues() {
|
|
5871
|
+
if (queues) return queues;
|
|
5872
|
+
queues = createIssueUploadQueues({
|
|
5873
|
+
api: createMediaUploadApi({ post: (endpoint, body) => apiClient.post(endpoint, body) }),
|
|
5874
|
+
clientInfo: "issue-sticker-sdk",
|
|
5875
|
+
videoStore: createIndexedDbPendingUploadStore(VIDEO_UPLOAD_DB_NAME),
|
|
5876
|
+
attachmentStore: createIndexedDbPendingUploadStore(ATTACHMENT_UPLOAD_DB_NAME),
|
|
5877
|
+
loadTus: loadTusClient,
|
|
5878
|
+
onEvent: (event) => {
|
|
5879
|
+
if (event.type !== "failed") invalidateIssueQueries(event.issueId);
|
|
5880
|
+
},
|
|
5881
|
+
onNotice: (notice) => toaster.show(notice, retryWidgetIssueUploads)
|
|
5882
|
+
});
|
|
5883
|
+
return queues;
|
|
5884
|
+
}
|
|
5885
|
+
function getWidgetVideoUploadQueue() {
|
|
5886
|
+
return getQueues().video;
|
|
5887
|
+
}
|
|
5888
|
+
function getWidgetAttachmentUploadQueue() {
|
|
5889
|
+
return getQueues().attachments;
|
|
5890
|
+
}
|
|
5891
|
+
function resumeWidgetIssueUploads(projectKey) {
|
|
5892
|
+
return getQueues().resume([projectKey]);
|
|
5893
|
+
}
|
|
5894
|
+
function retryWidgetIssueUploads(issueId) {
|
|
5895
|
+
queues == null ? void 0 : queues.retry(issueId);
|
|
5896
|
+
}
|
|
5897
|
+
function stopWidgetUploadQueues() {
|
|
5898
|
+
queues == null ? void 0 : queues.stop();
|
|
5899
|
+
queues = null;
|
|
5900
|
+
}
|
|
5130
5901
|
class EventBus {
|
|
5131
5902
|
constructor() {
|
|
5132
5903
|
this.listeners = /* @__PURE__ */ new Map();
|
|
@@ -5216,6 +5987,7 @@ const _SDKManager = class _SDKManager {
|
|
|
5216
5987
|
}
|
|
5217
5988
|
destroy() {
|
|
5218
5989
|
var _a;
|
|
5990
|
+
stopWidgetUploadQueues();
|
|
5219
5991
|
(_a = this._eventBus) == null ? void 0 : _a.removeAllListeners();
|
|
5220
5992
|
this._config = null;
|
|
5221
5993
|
this._platform = null;
|
|
@@ -5271,279 +6043,6 @@ function flushPendingSdkEventListeners(eventBus) {
|
|
|
5271
6043
|
});
|
|
5272
6044
|
pendingListeners.clear();
|
|
5273
6045
|
}
|
|
5274
|
-
function readApiBaseUrlFromEnv() {
|
|
5275
|
-
if (typeof process !== "undefined" && process.env && Object.prototype.hasOwnProperty.call(process.env, "VITE_API_BASE_URL")) {
|
|
5276
|
-
const processValue = process.env.VITE_API_BASE_URL;
|
|
5277
|
-
if (typeof processValue === "string") {
|
|
5278
|
-
const trimmed = processValue.trim();
|
|
5279
|
-
return trimmed.length > 0 && trimmed !== "undefined" ? trimmed : void 0;
|
|
5280
|
-
}
|
|
5281
|
-
}
|
|
5282
|
-
const viteValue = "https://api.issuesticker.com";
|
|
5283
|
-
{
|
|
5284
|
-
const trimmed = viteValue.trim();
|
|
5285
|
-
return trimmed.length > 0 && trimmed !== "undefined" ? trimmed : void 0;
|
|
5286
|
-
}
|
|
5287
|
-
}
|
|
5288
|
-
let tokenMemoryCache = null;
|
|
5289
|
-
let apiKeyCache = null;
|
|
5290
|
-
let sdkMode = null;
|
|
5291
|
-
let memberTokenProvider = null;
|
|
5292
|
-
function normalizeToken(token) {
|
|
5293
|
-
const trimmed = token.trim();
|
|
5294
|
-
if (trimmed.toLowerCase().startsWith("bearer ")) {
|
|
5295
|
-
return trimmed.slice(7).trim();
|
|
5296
|
-
}
|
|
5297
|
-
return trimmed;
|
|
5298
|
-
}
|
|
5299
|
-
function createMemberAuthRequiredError(message = "멤버 로그인이 필요합니다.") {
|
|
5300
|
-
return new ApiError(message, 401, {
|
|
5301
|
-
success: false,
|
|
5302
|
-
error: {
|
|
5303
|
-
code: "MEMBER_AUTH_REQUIRED",
|
|
5304
|
-
message
|
|
5305
|
-
}
|
|
5306
|
-
});
|
|
5307
|
-
}
|
|
5308
|
-
async function resolveAuthorizationHeader(options) {
|
|
5309
|
-
if (sdkMode === "public" || sdkMode === null) {
|
|
5310
|
-
if (apiKeyCache) {
|
|
5311
|
-
return `ApiKey ${apiKeyCache}`;
|
|
5312
|
-
}
|
|
5313
|
-
return void 0;
|
|
5314
|
-
}
|
|
5315
|
-
if (sdkMode === "member" && memberTokenProvider) {
|
|
5316
|
-
const token2 = await memberTokenProvider({
|
|
5317
|
-
forceRefresh: options == null ? void 0 : options.forceRefreshMemberToken,
|
|
5318
|
-
reason: (options == null ? void 0 : options.memberRefreshReason) || "missing"
|
|
5319
|
-
});
|
|
5320
|
-
if (!token2) {
|
|
5321
|
-
throw createMemberAuthRequiredError();
|
|
5322
|
-
}
|
|
5323
|
-
return `Bearer ${token2}`;
|
|
5324
|
-
}
|
|
5325
|
-
const token = tokenMemoryCache ? normalizeToken(tokenMemoryCache) : null;
|
|
5326
|
-
if (token) {
|
|
5327
|
-
return `Bearer ${token}`;
|
|
5328
|
-
}
|
|
5329
|
-
return void 0;
|
|
5330
|
-
}
|
|
5331
|
-
const isDemoMode = false;
|
|
5332
|
-
function getApiBaseUrl() {
|
|
5333
|
-
const baseUrl = readApiBaseUrlFromEnv();
|
|
5334
|
-
if (!baseUrl) {
|
|
5335
|
-
throw new ApiError(
|
|
5336
|
-
"API 서버 주소(VITE_API_BASE_URL)가 설정되지 않았습니다. SDK 빌드/환경을 확인해주세요.",
|
|
5337
|
-
0
|
|
5338
|
-
);
|
|
5339
|
-
}
|
|
5340
|
-
if (!/^https?:\/\//.test(baseUrl)) {
|
|
5341
|
-
throw new ApiError(`API 서버 주소(VITE_API_BASE_URL)가 올바르지 않습니다: ${baseUrl}`, 0);
|
|
5342
|
-
}
|
|
5343
|
-
return baseUrl.replace(/\/+$/, "");
|
|
5344
|
-
}
|
|
5345
|
-
function setApiKey(key) {
|
|
5346
|
-
apiKeyCache = key;
|
|
5347
|
-
}
|
|
5348
|
-
function setSdkMode(mode) {
|
|
5349
|
-
sdkMode = mode;
|
|
5350
|
-
}
|
|
5351
|
-
function getSdkMode() {
|
|
5352
|
-
return sdkMode;
|
|
5353
|
-
}
|
|
5354
|
-
function setMemberTokenProvider(provider) {
|
|
5355
|
-
memberTokenProvider = provider;
|
|
5356
|
-
}
|
|
5357
|
-
function assertRelativeApiEndpoint(endpoint) {
|
|
5358
|
-
if (!endpoint.startsWith("/") || endpoint.startsWith("//")) {
|
|
5359
|
-
throw new ApiError(`API endpoint는 백엔드 상대 경로여야 합니다: ${endpoint}`, 0);
|
|
5360
|
-
}
|
|
5361
|
-
}
|
|
5362
|
-
function buildApiUrl(endpoint) {
|
|
5363
|
-
assertRelativeApiEndpoint(endpoint);
|
|
5364
|
-
return `${getApiBaseUrl()}${endpoint}`;
|
|
5365
|
-
}
|
|
5366
|
-
async function saveToken(token) {
|
|
5367
|
-
const normalizedToken = normalizeToken(token);
|
|
5368
|
-
tokenMemoryCache = normalizedToken;
|
|
5369
|
-
}
|
|
5370
|
-
async function clearToken() {
|
|
5371
|
-
tokenMemoryCache = null;
|
|
5372
|
-
}
|
|
5373
|
-
class ApiError extends Error {
|
|
5374
|
-
constructor(message, status, data) {
|
|
5375
|
-
super(message);
|
|
5376
|
-
this.status = status;
|
|
5377
|
-
this.data = data;
|
|
5378
|
-
this.name = "ApiError";
|
|
5379
|
-
}
|
|
5380
|
-
}
|
|
5381
|
-
function extractErrorMessage(error) {
|
|
5382
|
-
if (!error) return void 0;
|
|
5383
|
-
if (typeof error === "string") return error;
|
|
5384
|
-
return error.message || error.code || JSON.stringify(error);
|
|
5385
|
-
}
|
|
5386
|
-
async function requestResponse(endpoint, options = {}) {
|
|
5387
|
-
const { body, skipAuth = false, headers: customHeaders, ...rest } = options;
|
|
5388
|
-
const headers = {
|
|
5389
|
-
"Content-Type": "application/json",
|
|
5390
|
-
"x-client-info": "issue-sticker-sdk",
|
|
5391
|
-
...customHeaders || {}
|
|
5392
|
-
};
|
|
5393
|
-
if (!skipAuth) {
|
|
5394
|
-
const authHeader = await resolveAuthorizationHeader();
|
|
5395
|
-
if (authHeader) {
|
|
5396
|
-
headers["Authorization"] = authHeader;
|
|
5397
|
-
}
|
|
5398
|
-
}
|
|
5399
|
-
const url = buildApiUrl(endpoint);
|
|
5400
|
-
const execute = (nextHeaders) => pristineFetch(url, {
|
|
5401
|
-
...rest,
|
|
5402
|
-
headers: nextHeaders,
|
|
5403
|
-
body: body ? JSON.stringify(body) : void 0
|
|
5404
|
-
});
|
|
5405
|
-
let response = await execute(headers);
|
|
5406
|
-
let retriedMemberAuth = false;
|
|
5407
|
-
if (!skipAuth && response.status === 401 && sdkMode === "member" && memberTokenProvider) {
|
|
5408
|
-
const retryHeaders = { ...headers };
|
|
5409
|
-
try {
|
|
5410
|
-
const authHeader = await resolveAuthorizationHeader({
|
|
5411
|
-
forceRefreshMemberToken: true,
|
|
5412
|
-
memberRefreshReason: "unauthorized"
|
|
5413
|
-
});
|
|
5414
|
-
if (authHeader) {
|
|
5415
|
-
retryHeaders.Authorization = authHeader;
|
|
5416
|
-
retriedMemberAuth = true;
|
|
5417
|
-
response = await execute(retryHeaders);
|
|
5418
|
-
}
|
|
5419
|
-
} catch {
|
|
5420
|
-
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5421
|
-
success: false,
|
|
5422
|
-
error: {
|
|
5423
|
-
code: "SESSION_EXPIRED",
|
|
5424
|
-
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5425
|
-
}
|
|
5426
|
-
});
|
|
5427
|
-
}
|
|
5428
|
-
}
|
|
5429
|
-
if (retriedMemberAuth && response.status === 401) {
|
|
5430
|
-
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5431
|
-
success: false,
|
|
5432
|
-
error: {
|
|
5433
|
-
code: "SESSION_EXPIRED",
|
|
5434
|
-
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5435
|
-
}
|
|
5436
|
-
});
|
|
5437
|
-
}
|
|
5438
|
-
if (response.status === 204) {
|
|
5439
|
-
return { success: true };
|
|
5440
|
-
}
|
|
5441
|
-
const json = await response.json();
|
|
5442
|
-
if (!response.ok || !json.success) {
|
|
5443
|
-
throw new ApiError(
|
|
5444
|
-
extractErrorMessage(json.error) || json.message || `요청 실패: ${response.status}`,
|
|
5445
|
-
response.status,
|
|
5446
|
-
json
|
|
5447
|
-
);
|
|
5448
|
-
}
|
|
5449
|
-
return json;
|
|
5450
|
-
}
|
|
5451
|
-
async function request(endpoint, options = {}) {
|
|
5452
|
-
const json = await requestResponse(endpoint, options);
|
|
5453
|
-
return json.data;
|
|
5454
|
-
}
|
|
5455
|
-
async function uploadRequest(endpoint, formData, skipAuth = false) {
|
|
5456
|
-
const headers = {
|
|
5457
|
-
"x-client-info": "issue-sticker-sdk"
|
|
5458
|
-
};
|
|
5459
|
-
if (!skipAuth) {
|
|
5460
|
-
const authHeader = await resolveAuthorizationHeader();
|
|
5461
|
-
if (authHeader) {
|
|
5462
|
-
headers["Authorization"] = authHeader;
|
|
5463
|
-
}
|
|
5464
|
-
}
|
|
5465
|
-
const url = buildApiUrl(endpoint);
|
|
5466
|
-
const execute = (nextHeaders) => pristineFetch(url, {
|
|
5467
|
-
method: "POST",
|
|
5468
|
-
headers: nextHeaders,
|
|
5469
|
-
body: formData
|
|
5470
|
-
});
|
|
5471
|
-
let response = await execute(headers);
|
|
5472
|
-
let retriedMemberAuth = false;
|
|
5473
|
-
if (!skipAuth && response.status === 401 && sdkMode === "member" && memberTokenProvider) {
|
|
5474
|
-
const retryHeaders = { ...headers };
|
|
5475
|
-
try {
|
|
5476
|
-
const authHeader = await resolveAuthorizationHeader({
|
|
5477
|
-
forceRefreshMemberToken: true,
|
|
5478
|
-
memberRefreshReason: "unauthorized"
|
|
5479
|
-
});
|
|
5480
|
-
if (authHeader) {
|
|
5481
|
-
retryHeaders.Authorization = authHeader;
|
|
5482
|
-
retriedMemberAuth = true;
|
|
5483
|
-
response = await execute(retryHeaders);
|
|
5484
|
-
}
|
|
5485
|
-
} catch {
|
|
5486
|
-
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5487
|
-
success: false,
|
|
5488
|
-
error: {
|
|
5489
|
-
code: "SESSION_EXPIRED",
|
|
5490
|
-
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5491
|
-
}
|
|
5492
|
-
});
|
|
5493
|
-
}
|
|
5494
|
-
}
|
|
5495
|
-
if (retriedMemberAuth && response.status === 401) {
|
|
5496
|
-
throw new ApiError("인증이 만료되었습니다. 다시 로그인해주세요.", 401, {
|
|
5497
|
-
success: false,
|
|
5498
|
-
error: {
|
|
5499
|
-
code: "SESSION_EXPIRED",
|
|
5500
|
-
message: "인증이 만료되었습니다. 다시 로그인해주세요."
|
|
5501
|
-
}
|
|
5502
|
-
});
|
|
5503
|
-
}
|
|
5504
|
-
const json = await response.json();
|
|
5505
|
-
if (!response.ok || !json.success) {
|
|
5506
|
-
throw new ApiError(
|
|
5507
|
-
extractErrorMessage(json.error) || json.message || `업로드 실패: ${response.status}`,
|
|
5508
|
-
response.status,
|
|
5509
|
-
json
|
|
5510
|
-
);
|
|
5511
|
-
}
|
|
5512
|
-
return json.data;
|
|
5513
|
-
}
|
|
5514
|
-
async function directUpload(signedUrl, file, contentType) {
|
|
5515
|
-
try {
|
|
5516
|
-
await directUploadToSignedUrl(signedUrl, file, contentType);
|
|
5517
|
-
} catch (error) {
|
|
5518
|
-
if (error instanceof ApiError) {
|
|
5519
|
-
throw error;
|
|
5520
|
-
}
|
|
5521
|
-
if (error instanceof DirectUploadError) {
|
|
5522
|
-
throw new ApiError(error.message, error.status, error.data);
|
|
5523
|
-
}
|
|
5524
|
-
throw new ApiError(error instanceof Error ? error.message : "스토리지 업로드 실패", 0, error);
|
|
5525
|
-
}
|
|
5526
|
-
}
|
|
5527
|
-
const apiClient = {
|
|
5528
|
-
get(endpoint, options) {
|
|
5529
|
-
return request(endpoint, { ...options, method: "GET" });
|
|
5530
|
-
},
|
|
5531
|
-
getResponse(endpoint, options) {
|
|
5532
|
-
return requestResponse(endpoint, { ...options, method: "GET" });
|
|
5533
|
-
},
|
|
5534
|
-
post(endpoint, body, options) {
|
|
5535
|
-
return request(endpoint, { ...options, method: "POST", body });
|
|
5536
|
-
},
|
|
5537
|
-
put(endpoint, body, options) {
|
|
5538
|
-
return request(endpoint, { ...options, method: "PUT", body });
|
|
5539
|
-
},
|
|
5540
|
-
delete(endpoint, options) {
|
|
5541
|
-
return request(endpoint, { ...options, method: "DELETE" });
|
|
5542
|
-
},
|
|
5543
|
-
upload(endpoint, formData, skipAuth) {
|
|
5544
|
-
return uploadRequest(endpoint, formData, skipAuth);
|
|
5545
|
-
}
|
|
5546
|
-
};
|
|
5547
6046
|
let session = null;
|
|
5548
6047
|
function resolveApiBaseUrl() {
|
|
5549
6048
|
try {
|
|
@@ -5710,25 +6209,6 @@ const createShadowRoot = (hostElement, cssTexts = []) => {
|
|
|
5710
6209
|
const getPortalContainer = () => {
|
|
5711
6210
|
return _portalTarget || document.body;
|
|
5712
6211
|
};
|
|
5713
|
-
const queryClient = new QueryClient({
|
|
5714
|
-
defaultOptions: {
|
|
5715
|
-
queries: {
|
|
5716
|
-
staleTime: 5 * 60 * 1e3,
|
|
5717
|
-
// 5분
|
|
5718
|
-
gcTime: 10 * 60 * 1e3,
|
|
5719
|
-
// 10분 (v5에서는 cacheTime 대신 gcTime 사용)
|
|
5720
|
-
refetchOnWindowFocus: true,
|
|
5721
|
-
refetchOnReconnect: true,
|
|
5722
|
-
retry: 3,
|
|
5723
|
-
retryDelay: (attemptIndex) => Math.min(1e3 * 2 ** attemptIndex, 3e4)
|
|
5724
|
-
},
|
|
5725
|
-
mutations: {
|
|
5726
|
-
retry: 1,
|
|
5727
|
-
// Mutation은 1번만 재시도
|
|
5728
|
-
retryDelay: 1e3
|
|
5729
|
-
}
|
|
5730
|
-
}
|
|
5731
|
-
});
|
|
5732
6212
|
/**
|
|
5733
6213
|
* @license lucide-react v0.562.0 - ISC
|
|
5734
6214
|
*
|
|
@@ -14657,7 +15137,10 @@ const ToastItem = forwardRef(function ToastItem2({ t, behindCount, onDismiss },
|
|
|
14657
15137
|
),
|
|
14658
15138
|
children: /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center gap-2.5 px-3 py-2.5", style.tint), children: [
|
|
14659
15139
|
t.type !== "default" ? /* @__PURE__ */ jsx(Icon2, { className: cn$1("h-4 w-4 shrink-0", style.iconColor) }) : null,
|
|
14660
|
-
/* @__PURE__ */
|
|
15140
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 text-sm text-text-primary", children: [
|
|
15141
|
+
t.title ? /* @__PURE__ */ jsx("span", { className: "block font-semibold", children: t.title }) : null,
|
|
15142
|
+
/* @__PURE__ */ jsx("span", { className: t.title ? "block" : "font-medium", children: t.message })
|
|
15143
|
+
] }),
|
|
14661
15144
|
t.action ? /* @__PURE__ */ jsx(
|
|
14662
15145
|
"button",
|
|
14663
15146
|
{
|
|
@@ -14765,235 +15248,6 @@ function toIssueFilterParams(filters) {
|
|
|
14765
15248
|
...countRecord(filters.notionFieldValues) ? { notionFieldValues: filters.notionFieldValues } : {}
|
|
14766
15249
|
};
|
|
14767
15250
|
}
|
|
14768
|
-
async function uploadSignedMedia(file, mediaType, issueId) {
|
|
14769
|
-
return uploadSignedMediaWithApi(
|
|
14770
|
-
{
|
|
14771
|
-
post: (endpoint, body) => apiClient.post(endpoint, body),
|
|
14772
|
-
directUpload
|
|
14773
|
-
},
|
|
14774
|
-
file,
|
|
14775
|
-
mediaType,
|
|
14776
|
-
{ issueId }
|
|
14777
|
-
);
|
|
14778
|
-
}
|
|
14779
|
-
function issuesEndpoint() {
|
|
14780
|
-
return "/api/sdk/issues";
|
|
14781
|
-
}
|
|
14782
|
-
function guestOwnerQuery() {
|
|
14783
|
-
var _a;
|
|
14784
|
-
const mode = getSdkMode();
|
|
14785
|
-
if (mode !== "public") return "";
|
|
14786
|
-
return buildGuestOwnerQuery(mode, (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id);
|
|
14787
|
-
}
|
|
14788
|
-
let issuesCache = null;
|
|
14789
|
-
const CACHE_DURATION_MS = 30 * 1e3;
|
|
14790
|
-
const STICKER_PAGE_SIZE = 500;
|
|
14791
|
-
const STICKER_FETCH_LIMIT = 2e3;
|
|
14792
|
-
function getFilterKey(filters) {
|
|
14793
|
-
var _a;
|
|
14794
|
-
const normalizeArray = (value) => {
|
|
14795
|
-
if (value === "all" || !value) return "all";
|
|
14796
|
-
if (Array.isArray(value)) {
|
|
14797
|
-
return value.length === 0 ? "all" : [...value].sort().join(",");
|
|
14798
|
-
}
|
|
14799
|
-
return String(value);
|
|
14800
|
-
};
|
|
14801
|
-
const normalizeRecord = (record) => {
|
|
14802
|
-
if (!record) return "";
|
|
14803
|
-
const entries = Object.entries(record).map(([k, v]) => [k, [...v].sort()]).sort(([a], [b]) => a.localeCompare(b));
|
|
14804
|
-
return JSON.stringify(entries);
|
|
14805
|
-
};
|
|
14806
|
-
return JSON.stringify({
|
|
14807
|
-
sdkMode: getSdkMode() || "public",
|
|
14808
|
-
url: normalizeArray(filters.url),
|
|
14809
|
-
projectId: filters.projectId || "all",
|
|
14810
|
-
externalUserId: filters.externalUserId || "",
|
|
14811
|
-
search: ((_a = filters.search) == null ? void 0 : _a.trim()) || "",
|
|
14812
|
-
dateFrom: filters.dateFrom || "",
|
|
14813
|
-
dateTo: filters.dateTo || "",
|
|
14814
|
-
page: filters.page ?? 0,
|
|
14815
|
-
pageSize: filters.pageSize ?? 0,
|
|
14816
|
-
custom: normalizeRecord(filters.customFieldValues),
|
|
14817
|
-
jira: normalizeRecord(filters.jiraFieldValues),
|
|
14818
|
-
notion: normalizeRecord(filters.notionFieldValues),
|
|
14819
|
-
sortOrder: filters.sortOrder || ""
|
|
14820
|
-
});
|
|
14821
|
-
}
|
|
14822
|
-
function invalidateIssuesCache() {
|
|
14823
|
-
issuesCache = null;
|
|
14824
|
-
}
|
|
14825
|
-
function recordToFilterArray(record, keyFieldName) {
|
|
14826
|
-
if (!record) return null;
|
|
14827
|
-
const entries = Object.entries(record).filter(([, values]) => values.length > 0);
|
|
14828
|
-
if (entries.length === 0) return null;
|
|
14829
|
-
return entries.map(
|
|
14830
|
-
([key, values]) => ({ [keyFieldName]: key, values })
|
|
14831
|
-
);
|
|
14832
|
-
}
|
|
14833
|
-
function buildFilterQueryParams(filters) {
|
|
14834
|
-
var _a;
|
|
14835
|
-
const params = new URLSearchParams();
|
|
14836
|
-
if (filters.projectId) {
|
|
14837
|
-
params.set("project_id", filters.projectId);
|
|
14838
|
-
}
|
|
14839
|
-
if (filters.url && filters.url !== "all") {
|
|
14840
|
-
if (Array.isArray(filters.url) && filters.url.length > 0) {
|
|
14841
|
-
params.set("url", filters.url.join(","));
|
|
14842
|
-
} else if (typeof filters.url === "string") {
|
|
14843
|
-
params.set("url", filters.url);
|
|
14844
|
-
}
|
|
14845
|
-
}
|
|
14846
|
-
const search2 = (_a = filters.search) == null ? void 0 : _a.trim();
|
|
14847
|
-
if (search2) {
|
|
14848
|
-
params.set("search", search2);
|
|
14849
|
-
}
|
|
14850
|
-
if (filters.dateFrom) {
|
|
14851
|
-
params.set("date_from", filters.dateFrom);
|
|
14852
|
-
}
|
|
14853
|
-
if (filters.dateTo) {
|
|
14854
|
-
params.set("date_to", filters.dateTo);
|
|
14855
|
-
}
|
|
14856
|
-
const customArr = recordToFilterArray(filters.customFieldValues, "fieldDefinitionId");
|
|
14857
|
-
if (customArr) {
|
|
14858
|
-
params.set("custom_field_filters", JSON.stringify(customArr));
|
|
14859
|
-
}
|
|
14860
|
-
const jiraArr = recordToFilterArray(filters.jiraFieldValues, "fieldName");
|
|
14861
|
-
if (jiraArr) {
|
|
14862
|
-
params.set("jira_field_filters", JSON.stringify(jiraArr));
|
|
14863
|
-
}
|
|
14864
|
-
const notionArr = recordToFilterArray(filters.notionFieldValues, "fieldName");
|
|
14865
|
-
if (notionArr) {
|
|
14866
|
-
params.set("notion_field_filters", JSON.stringify(notionArr));
|
|
14867
|
-
}
|
|
14868
|
-
if (filters.externalUserId) {
|
|
14869
|
-
params.set("external_user_id", filters.externalUserId);
|
|
14870
|
-
}
|
|
14871
|
-
if (typeof filters.page === "number" && filters.page > 0) {
|
|
14872
|
-
params.set("page", String(filters.page));
|
|
14873
|
-
}
|
|
14874
|
-
if (typeof filters.pageSize === "number" && filters.pageSize > 0) {
|
|
14875
|
-
params.set("page_size", String(filters.pageSize));
|
|
14876
|
-
}
|
|
14877
|
-
if (filters.sortOrder) {
|
|
14878
|
-
params.set("sort_order", filters.sortOrder);
|
|
14879
|
-
}
|
|
14880
|
-
const queryString = params.toString();
|
|
14881
|
-
return queryString ? `?${queryString}` : "";
|
|
14882
|
-
}
|
|
14883
|
-
const issueService = {
|
|
14884
|
-
async createIssue(issueData) {
|
|
14885
|
-
const sanitizedData = sanitizeString(issueData);
|
|
14886
|
-
const screenshotUploadIds = (sanitizedData.screenshot || []).map((url) => getRegisteredUploadId(url, "screenshot")).filter((id2) => typeof id2 === "string" && id2.length > 0);
|
|
14887
|
-
const videoUploadId = sanitizedData.video ? getRegisteredUploadId(sanitizedData.video, "video") : void 0;
|
|
14888
|
-
if (screenshotUploadIds.length > 0) {
|
|
14889
|
-
sanitizedData.screenshot_upload_ids = screenshotUploadIds;
|
|
14890
|
-
}
|
|
14891
|
-
if (videoUploadId) {
|
|
14892
|
-
sanitizedData.video_upload_id = videoUploadId;
|
|
14893
|
-
}
|
|
14894
|
-
const issue = await apiClient.post(issuesEndpoint(), sanitizedData);
|
|
14895
|
-
invalidateIssuesCache();
|
|
14896
|
-
return issue;
|
|
14897
|
-
},
|
|
14898
|
-
async getIssues(filters = {}, options = {}) {
|
|
14899
|
-
if (!filters.projectId) {
|
|
14900
|
-
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
14901
|
-
}
|
|
14902
|
-
const filterKey = getFilterKey(filters);
|
|
14903
|
-
const now2 = Date.now();
|
|
14904
|
-
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
14905
|
-
return issuesCache.data;
|
|
14906
|
-
}
|
|
14907
|
-
const queryParams = buildFilterQueryParams(filters);
|
|
14908
|
-
const { items: issues = [] } = await apiClient.get(
|
|
14909
|
-
`${issuesEndpoint()}${queryParams}`
|
|
14910
|
-
);
|
|
14911
|
-
issuesCache = {
|
|
14912
|
-
data: issues,
|
|
14913
|
-
timestamp: now2,
|
|
14914
|
-
filterKey
|
|
14915
|
-
};
|
|
14916
|
-
return issues;
|
|
14917
|
-
},
|
|
14918
|
-
async getIssueStickers(filters = {}, options = {}) {
|
|
14919
|
-
var _a, _b2;
|
|
14920
|
-
if (!filters.projectId) {
|
|
14921
|
-
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
14922
|
-
}
|
|
14923
|
-
const filterKey = `${getFilterKey(filters)}:stickers`;
|
|
14924
|
-
const now2 = Date.now();
|
|
14925
|
-
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
14926
|
-
return issuesCache.data;
|
|
14927
|
-
}
|
|
14928
|
-
const issues = [];
|
|
14929
|
-
let page = 1;
|
|
14930
|
-
let hasMore = true;
|
|
14931
|
-
while (hasMore && issues.length <= STICKER_FETCH_LIMIT) {
|
|
14932
|
-
const response = await apiClient.getResponse(
|
|
14933
|
-
`${issuesEndpoint()}/stickers${buildFilterQueryParams({
|
|
14934
|
-
...filters,
|
|
14935
|
-
page,
|
|
14936
|
-
pageSize: STICKER_PAGE_SIZE
|
|
14937
|
-
})}`
|
|
14938
|
-
);
|
|
14939
|
-
const pageItems = ((_a = response.data) == null ? void 0 : _a.items) ?? [];
|
|
14940
|
-
issues.push(...pageItems);
|
|
14941
|
-
hasMore = Boolean((_b2 = response.data) == null ? void 0 : _b2.hasMore) && pageItems.length > 0;
|
|
14942
|
-
page += 1;
|
|
14943
|
-
}
|
|
14944
|
-
issuesCache = {
|
|
14945
|
-
data: issues,
|
|
14946
|
-
timestamp: now2,
|
|
14947
|
-
filterKey
|
|
14948
|
-
};
|
|
14949
|
-
return issues;
|
|
14950
|
-
},
|
|
14951
|
-
invalidateCache() {
|
|
14952
|
-
invalidateIssuesCache();
|
|
14953
|
-
},
|
|
14954
|
-
// 계약 기준: 백엔드 GET /api/sdk/issues/:id 는 back#101부터 읽기-시점-스크럽된
|
|
14955
|
-
// llm_prompt 를 상세 응답에 포함한다(목록 응답에는 없음) — 스코프를 이 반환 타입에만 한정한다.
|
|
14956
|
-
async getIssue(id2) {
|
|
14957
|
-
return apiClient.get(
|
|
14958
|
-
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`
|
|
14959
|
-
);
|
|
14960
|
-
},
|
|
14961
|
-
async updateIssue(id2, updates) {
|
|
14962
|
-
const sanitizedUpdates = sanitizeString(updates);
|
|
14963
|
-
const issue = await apiClient.put(
|
|
14964
|
-
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`,
|
|
14965
|
-
sanitizedUpdates
|
|
14966
|
-
);
|
|
14967
|
-
invalidateIssuesCache();
|
|
14968
|
-
return issue;
|
|
14969
|
-
},
|
|
14970
|
-
/**
|
|
14971
|
-
* 재생성. 스펙상 세 채널 모두에서 되고 역할과 무관하다 — 검사는 역할이 아니라
|
|
14972
|
-
* 그 이슈에 접근할 수 있는지다(백엔드가 판정한다).
|
|
14973
|
-
*
|
|
14974
|
-
* 응답으로 갱신된 이슈가 오지만 상태는 다시 pending 이다. 호출부는 응답을
|
|
14975
|
-
* 그대로 쓰지 말고 폴링으로 이어받아야 한다.
|
|
14976
|
-
*/
|
|
14977
|
-
async regenerateIssue(id2) {
|
|
14978
|
-
const issue = await apiClient.post(
|
|
14979
|
-
`${issuesEndpoint()}/${encodeURIComponent(id2)}/regenerate${guestOwnerQuery()}`,
|
|
14980
|
-
{}
|
|
14981
|
-
);
|
|
14982
|
-
invalidateIssuesCache();
|
|
14983
|
-
return issue;
|
|
14984
|
-
},
|
|
14985
|
-
async deleteIssue(id2, options) {
|
|
14986
|
-
const endpoint = `${issuesEndpoint()}/${id2}${guestOwnerQuery()}`;
|
|
14987
|
-
if (options == null ? void 0 : options.deleteExternal) {
|
|
14988
|
-
await apiClient.delete(endpoint, {
|
|
14989
|
-
body: { deleteExternal: true }
|
|
14990
|
-
});
|
|
14991
|
-
} else {
|
|
14992
|
-
await apiClient.delete(endpoint);
|
|
14993
|
-
}
|
|
14994
|
-
invalidateIssuesCache();
|
|
14995
|
-
}
|
|
14996
|
-
};
|
|
14997
15251
|
async function loadIssuesFromServer(url, projectId, externalUserId, filters, options = {}) {
|
|
14998
15252
|
if (!projectId) return [];
|
|
14999
15253
|
try {
|
|
@@ -15171,18 +15425,18 @@ function UnrenderedStickerDialog({
|
|
|
15171
15425
|
{
|
|
15172
15426
|
role: "dialog",
|
|
15173
15427
|
"aria-modal": "false",
|
|
15174
|
-
"aria-label": "
|
|
15428
|
+
"aria-label": "표시하지 못한 스티커 목록",
|
|
15175
15429
|
className: "pointer-events-auto flex h-[min(480px,calc(100vh-64px))] w-[min(560px,calc(100vw-32px))] flex-col overflow-hidden rounded-xl border border-slate-200 bg-white text-slate-900 shadow-2xl",
|
|
15176
15430
|
children: [
|
|
15177
15431
|
/* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between border-b border-slate-100 px-5 py-3.5", children: [
|
|
15178
|
-
/* @__PURE__ */ jsx("h2", { className: "min-w-0 truncate text-sm font-semibold", children: "
|
|
15432
|
+
/* @__PURE__ */ jsx("h2", { className: "min-w-0 truncate text-sm font-semibold", children: "표시하지 못한 스티커" }),
|
|
15179
15433
|
/* @__PURE__ */ jsx(
|
|
15180
15434
|
"button",
|
|
15181
15435
|
{
|
|
15182
15436
|
type: "button",
|
|
15183
15437
|
className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-slate-500 hover:bg-slate-100 hover:text-slate-900",
|
|
15184
15438
|
onClick: () => onOpenChange(false),
|
|
15185
|
-
"aria-label": "
|
|
15439
|
+
"aria-label": "표시하지 못한 스티커 목록 닫기",
|
|
15186
15440
|
children: /* @__PURE__ */ jsx(X$1, { className: "h-4 w-4" })
|
|
15187
15441
|
}
|
|
15188
15442
|
)
|
|
@@ -15360,7 +15614,8 @@ function OverlayShell({
|
|
|
15360
15614
|
}
|
|
15361
15615
|
const ISSUE_DRAFT_DISABLED_MESSAGE = "지금은 AI 작성을 사용할 수 없습니다. 제목과 설명을 직접 작성해주세요.";
|
|
15362
15616
|
const LABEL = "기대한 동작";
|
|
15363
|
-
const
|
|
15617
|
+
const ISSUE_INTENT_PLACEHOLDER = "기대한 동작을 적으면 AI가 제목과 설명을 작성합니다.\n예: 쿠폰을 적용하면 결제 금액이 바로 줄어야 합니다";
|
|
15618
|
+
const PLACEHOLDER = ISSUE_INTENT_PLACEHOLDER;
|
|
15364
15619
|
const SWITCH_TO_MANUAL = "직접 작성";
|
|
15365
15620
|
const SWITCH_TO_MANUAL_TOOLTIP = "제목, 설명 등 이슈 필드를 직접 작성합니다";
|
|
15366
15621
|
const SUBMIT = "보내기";
|
|
@@ -15397,20 +15652,28 @@ function IssueIntentBubble({
|
|
|
15397
15652
|
if (isFocused(node2) || Date.now() >= deadline) return;
|
|
15398
15653
|
frame2 = requestAnimationFrame(attempt);
|
|
15399
15654
|
};
|
|
15400
|
-
|
|
15655
|
+
const pointerScopes = /* @__PURE__ */ new Set([window, node2.getRootNode()]);
|
|
15656
|
+
pointerScopes.forEach(
|
|
15657
|
+
(scope) => scope.addEventListener("pointerdown", abandon, { capture: true })
|
|
15658
|
+
);
|
|
15401
15659
|
window.addEventListener("keydown", abandon, { capture: true });
|
|
15402
15660
|
attempt();
|
|
15403
15661
|
return () => {
|
|
15404
|
-
|
|
15662
|
+
pointerScopes.forEach(
|
|
15663
|
+
(scope) => scope.removeEventListener("pointerdown", abandon, { capture: true })
|
|
15664
|
+
);
|
|
15405
15665
|
window.removeEventListener("keydown", abandon, { capture: true });
|
|
15406
15666
|
if (frame2) cancelAnimationFrame(frame2);
|
|
15407
15667
|
};
|
|
15408
15668
|
}, []);
|
|
15669
|
+
const minHeightRef = useRef(null);
|
|
15409
15670
|
useLayoutEffect(() => {
|
|
15410
15671
|
const node2 = inputRef.current;
|
|
15411
15672
|
if (!node2) return;
|
|
15412
15673
|
node2.style.height = "auto";
|
|
15413
|
-
|
|
15674
|
+
minHeightRef.current ?? (minHeightRef.current = node2.scrollHeight);
|
|
15675
|
+
const next = Math.max(node2.scrollHeight, minHeightRef.current);
|
|
15676
|
+
node2.style.height = `${Math.min(next, MAX_INPUT_HEIGHT)}px`;
|
|
15414
15677
|
}, [value]);
|
|
15415
15678
|
return (
|
|
15416
15679
|
/*
|
|
@@ -15426,7 +15689,7 @@ function IssueIntentBubble({
|
|
|
15426
15689
|
/* @__PURE__ */ jsxs(
|
|
15427
15690
|
"div",
|
|
15428
15691
|
{
|
|
15429
|
-
className: `${ISSUE_STICKER_REPORT_FORM_CLASS} w-[min(
|
|
15692
|
+
className: `${ISSUE_STICKER_REPORT_FORM_CLASS} w-[min(24rem,calc(100vw_-_1.5rem))] space-y-1.5 rounded-md border border-line-subtle bg-surface-1 p-1.5 transition-colors duration-fast ease-out focus-within:border-line-focus`,
|
|
15430
15693
|
children: [
|
|
15431
15694
|
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1.5", children: [
|
|
15432
15695
|
/* @__PURE__ */ jsx(
|
|
@@ -15736,7 +15999,9 @@ DialogClose$1.displayName = CLOSE_NAME;
|
|
|
15736
15999
|
function getState$2(open) {
|
|
15737
16000
|
return open ? "open" : "closed";
|
|
15738
16001
|
}
|
|
15739
|
-
const Dialog = Dialog$1
|
|
16002
|
+
const [Dialog, useDialogContentDismissRef] = createShadowDismissRoot(Dialog$1, {
|
|
16003
|
+
focusOutside: false
|
|
16004
|
+
});
|
|
15740
16005
|
const DialogClose = DialogClose$1;
|
|
15741
16006
|
const DialogPortal = ({ children }) => {
|
|
15742
16007
|
const portalContainer = usePortalContainer();
|
|
@@ -15769,13 +16034,13 @@ const DialogContent = React.forwardRef(
|
|
|
15769
16034
|
...props
|
|
15770
16035
|
}, ref) => {
|
|
15771
16036
|
const [content2, setContent] = React.useState(null);
|
|
16037
|
+
const dismissRef = useDialogContentDismissRef(ref);
|
|
15772
16038
|
const composedRef = React.useCallback(
|
|
15773
16039
|
(node2) => {
|
|
15774
16040
|
setContent(node2);
|
|
15775
|
-
|
|
15776
|
-
else if (ref) ref.current = node2;
|
|
16041
|
+
dismissRef(node2);
|
|
15777
16042
|
},
|
|
15778
|
-
[
|
|
16043
|
+
[dismissRef]
|
|
15779
16044
|
);
|
|
15780
16045
|
useOverlayFocus({ enabled: true, container: content2, initialFocusRef });
|
|
15781
16046
|
return /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
@@ -16048,7 +16313,11 @@ function appendSnippet(base, body) {
|
|
|
16048
16313
|
${trimmedBody}`;
|
|
16049
16314
|
}
|
|
16050
16315
|
const TRIGGER_LABEL = "고정 문구 선택";
|
|
16316
|
+
const TRIGGER_HINT = "이슈 설명 끝에 추가할 고정 문구를 선택합니다";
|
|
16051
16317
|
const CLEAR_OPTION_LABEL = "선택 안 함";
|
|
16318
|
+
const EMPTY_TITLE = "등록된 고정 문구가 없습니다";
|
|
16319
|
+
const EMPTY_DESCRIPTION = "테스트 계정처럼 이슈마다 반복해서 적는 내용을 등록해두면 이슈 설명 끝에 추가됩니다.";
|
|
16320
|
+
const DEFAULT_EMPTY_HINT = "어드민 프로젝트 상세의 고정 문구 탭에서 등록합니다.";
|
|
16052
16321
|
const GROUP_LABEL = {
|
|
16053
16322
|
project: "공용 문구",
|
|
16054
16323
|
personal: "내 문구"
|
|
@@ -16057,7 +16326,8 @@ function SnippetPicker({
|
|
|
16057
16326
|
snippets,
|
|
16058
16327
|
selectedId,
|
|
16059
16328
|
onSelect,
|
|
16060
|
-
disabled = false
|
|
16329
|
+
disabled = false,
|
|
16330
|
+
emptyHint = DEFAULT_EMPTY_HINT
|
|
16061
16331
|
}) {
|
|
16062
16332
|
const [open, setOpen] = useState(false);
|
|
16063
16333
|
const listRef = useRef(null);
|
|
@@ -16116,7 +16386,8 @@ function SnippetPicker({
|
|
|
16116
16386
|
"button",
|
|
16117
16387
|
{
|
|
16118
16388
|
type: "button",
|
|
16119
|
-
|
|
16389
|
+
title: TRIGGER_HINT,
|
|
16390
|
+
disabled,
|
|
16120
16391
|
className: cn$1(
|
|
16121
16392
|
"inline-flex max-w-[10rem] items-center gap-1 rounded-sm border border-transparent px-2 py-1 text-xs text-text-secondary outline-none",
|
|
16122
16393
|
"hover:bg-surface-2 focus-visible:border-line-focus disabled:cursor-not-allowed disabled:opacity-40"
|
|
@@ -16134,8 +16405,18 @@ function SnippetPicker({
|
|
|
16134
16405
|
align: "start",
|
|
16135
16406
|
sideOffset: 4,
|
|
16136
16407
|
onEscapeKeyDown: stopEscapePropagation(),
|
|
16137
|
-
className: cn$1(
|
|
16138
|
-
|
|
16408
|
+
className: cn$1(
|
|
16409
|
+
`panel-shell-subtle p-1.5 shadow-lg ${OVERLAY_LAYER.floating}`,
|
|
16410
|
+
isEmpty ? "w-[min(30rem,calc(100vw_-_1.5rem))]" : "w-72"
|
|
16411
|
+
),
|
|
16412
|
+
children: isEmpty ? (
|
|
16413
|
+
// 비어 있다고 버튼을 막으면 무엇을 하는 버튼인지조차 알 수 없다. 열어서 이유를 알려준다.
|
|
16414
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1 break-keep px-2.5 py-2 [overflow-wrap:anywhere]", children: [
|
|
16415
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-text-primary", children: EMPTY_TITLE }),
|
|
16416
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: EMPTY_DESCRIPTION }),
|
|
16417
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: emptyHint })
|
|
16418
|
+
] })
|
|
16419
|
+
) : /* @__PURE__ */ jsxs(
|
|
16139
16420
|
"div",
|
|
16140
16421
|
{
|
|
16141
16422
|
ref: listRef,
|
|
@@ -16531,6 +16812,16 @@ async function captureScreenshot(options) {
|
|
|
16531
16812
|
}
|
|
16532
16813
|
return void 0;
|
|
16533
16814
|
}
|
|
16815
|
+
async function captureViewportAndElement(element2, excludeSelectors) {
|
|
16816
|
+
try {
|
|
16817
|
+
if (SDKManager.getInstance().isInitialized()) {
|
|
16818
|
+
return await captureViewportWithElementCrop({ element: element2, excludeSelectors });
|
|
16819
|
+
}
|
|
16820
|
+
} catch (err) {
|
|
16821
|
+
devLogger.error("screenshotCapture", "스크린샷 캡처 실패:", err);
|
|
16822
|
+
}
|
|
16823
|
+
return {};
|
|
16824
|
+
}
|
|
16534
16825
|
function toScreenshotList(dataUrls, dataUrl) {
|
|
16535
16826
|
if (dataUrls && dataUrls.length > 0) {
|
|
16536
16827
|
return dataUrls;
|
|
@@ -16652,15 +16943,17 @@ function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
|
16652
16943
|
useEffect(() => {
|
|
16653
16944
|
const captureScreenshotsInBackground = async (position2) => {
|
|
16654
16945
|
await waitForFormOpen();
|
|
16655
|
-
const
|
|
16656
|
-
|
|
16657
|
-
|
|
16658
|
-
|
|
16659
|
-
|
|
16660
|
-
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16946
|
+
const { fullScreenshotDataUrl, elementScreenshotDataUrl } = await pauseNetworkLogCollectionWhile(async () => {
|
|
16947
|
+
const { fullDataUrl, elementDataUrl } = await captureViewportAndElement(
|
|
16948
|
+
position2.element,
|
|
16949
|
+
SCREENSHOT_EXCLUDE_SELECTORS
|
|
16950
|
+
);
|
|
16951
|
+
const element2 = elementDataUrl ?? await captureScreenshot({
|
|
16952
|
+
element: position2.element,
|
|
16953
|
+
excludeSelectors: SCREENSHOT_EXCLUDE_SELECTORS
|
|
16954
|
+
});
|
|
16955
|
+
return { fullScreenshotDataUrl: fullDataUrl, elementScreenshotDataUrl: element2 };
|
|
16956
|
+
});
|
|
16664
16957
|
const captured = {
|
|
16665
16958
|
screenshotDataUrl: elementScreenshotDataUrl,
|
|
16666
16959
|
screenshotDataUrls: [fullScreenshotDataUrl, elementScreenshotDataUrl].filter(
|
|
@@ -16787,43 +17080,6 @@ function useScreenshotUpload() {
|
|
|
16787
17080
|
uploadMany
|
|
16788
17081
|
};
|
|
16789
17082
|
}
|
|
16790
|
-
async function uploadVideo(videoFile, issueId) {
|
|
16791
|
-
devLogger.log("videoUpload", "영상 파일 업로드 시작", {
|
|
16792
|
-
크기: `${(videoFile.size / 1024 / 1024).toFixed(2)}MB`,
|
|
16793
|
-
타입: videoFile.type
|
|
16794
|
-
});
|
|
16795
|
-
const result = await uploadSignedMedia(videoFile, "video", issueId);
|
|
16796
|
-
devLogger.log("videoUpload", "영상 파일 업로드 성공:", result.url);
|
|
16797
|
-
return result.url;
|
|
16798
|
-
}
|
|
16799
|
-
function useVideoUpload() {
|
|
16800
|
-
const upload = async (videoFile) => uploadVideo(videoFile);
|
|
16801
|
-
return {
|
|
16802
|
-
upload
|
|
16803
|
-
};
|
|
16804
|
-
}
|
|
16805
|
-
async function uploadSessionReplay(snapshot) {
|
|
16806
|
-
try {
|
|
16807
|
-
const file = new File([snapshot.payload], "session-replay.gz", {
|
|
16808
|
-
type: "application/gzip"
|
|
16809
|
-
});
|
|
16810
|
-
const { id: id2 } = await uploadSignedMedia(file, "replay");
|
|
16811
|
-
const marker = readReleaseMarker();
|
|
16812
|
-
return {
|
|
16813
|
-
uploadId: id2,
|
|
16814
|
-
meta: {
|
|
16815
|
-
window_seconds: snapshot.windowSeconds,
|
|
16816
|
-
event_count: snapshot.eventCount,
|
|
16817
|
-
size_bytes: snapshot.sizeBytes,
|
|
16818
|
-
rrweb_version: snapshot.rrwebVersion,
|
|
16819
|
-
privacy_config_version: snapshot.privacyConfigVersion,
|
|
16820
|
-
...marker ? { release: marker.release, release_source: marker.release_source } : {}
|
|
16821
|
-
}
|
|
16822
|
-
};
|
|
16823
|
-
} catch {
|
|
16824
|
-
return null;
|
|
16825
|
-
}
|
|
16826
|
-
}
|
|
16827
17083
|
function assertSubmittable(data) {
|
|
16828
17084
|
var _a, _b2, _c2;
|
|
16829
17085
|
const hasIntent = Boolean((_a = data.intent) == null ? void 0 : _a.trim());
|
|
@@ -16849,18 +17105,13 @@ function useIssueSubmission({
|
|
|
16849
17105
|
const { fetchConsoleLogs } = useConsoleLogs();
|
|
16850
17106
|
const { getAuthInfo } = useAuthInfo();
|
|
16851
17107
|
const { uploadMany: uploadScreenshots2 } = useScreenshotUpload();
|
|
16852
|
-
const { upload: uploadVideo2 } = useVideoUpload();
|
|
16853
17108
|
const createIssueMutation = useDebouncedMutation({
|
|
16854
17109
|
mutationFn: async (data) => {
|
|
16855
17110
|
var _a, _b2, _c2, _d2, _e2, _f2;
|
|
16856
17111
|
assertSubmittable(data);
|
|
16857
17112
|
let screenshotUrls;
|
|
16858
|
-
|
|
16859
|
-
if (
|
|
16860
|
-
videoUrl = await uploadVideo2(data.videoFile);
|
|
16861
|
-
} else if (data.position.videoFile) {
|
|
16862
|
-
videoUrl = await uploadVideo2(data.position.videoFile);
|
|
16863
|
-
} else {
|
|
17113
|
+
const videoFile2 = data.videoFile ?? data.position.videoFile;
|
|
17114
|
+
if (!videoFile2) {
|
|
16864
17115
|
const screenshotDataUrls = await resolveClickPositionScreenshots(data.position);
|
|
16865
17116
|
if (screenshotDataUrls.length > 0) {
|
|
16866
17117
|
const uploadedUrls = await uploadScreenshots2(screenshotDataUrls, {
|
|
@@ -16901,7 +17152,7 @@ function useIssueSubmission({
|
|
|
16901
17152
|
component: positionData.component
|
|
16902
17153
|
},
|
|
16903
17154
|
screenshot: screenshotUrls && screenshotUrls.length > 0 ? screenshotUrls : void 0,
|
|
16904
|
-
|
|
17155
|
+
...videoFile2 ? { video_pending: true } : {},
|
|
16905
17156
|
network_logs: networkLogs,
|
|
16906
17157
|
console_logs: consoleLogs.length > 0 ? consoleLogs : void 0,
|
|
16907
17158
|
user_agent: userAgent,
|
|
@@ -16916,39 +17167,17 @@ function useIssueSubmission({
|
|
|
16916
17167
|
if (((_e2 = issueData.custom_field_values) == null ? void 0 : _e2.length) === 0) {
|
|
16917
17168
|
delete issueData.custom_field_values;
|
|
16918
17169
|
}
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
devLogger.error(
|
|
16931
|
-
"useIssueSubmission",
|
|
16932
|
-
"세션 리플레이 첨부 실패 (이슈 생성 계속):",
|
|
16933
|
-
replayError
|
|
16934
|
-
);
|
|
16935
|
-
}
|
|
16936
|
-
}
|
|
16937
|
-
try {
|
|
16938
|
-
const socketSnapshot = await serializeSocketTranscript(
|
|
16939
|
-
getCollectorSession().socket.getConnections()
|
|
16940
|
-
);
|
|
16941
|
-
if (socketSnapshot) {
|
|
16942
|
-
const uploaded = await uploadSocketTranscript(
|
|
16943
|
-
{ post: (endpoint, body) => apiClient.post(endpoint, body), directUpload },
|
|
16944
|
-
socketSnapshot
|
|
16945
|
-
);
|
|
16946
|
-
if (uploaded) {
|
|
16947
|
-
issueData.socket_log_upload_id = uploaded.uploadId;
|
|
16948
|
-
}
|
|
16949
|
-
}
|
|
16950
|
-
} catch (socketError) {
|
|
16951
|
-
devLogger.error("useIssueSubmission", "소켓 전사 첨부 실패 (이슈 생성 계속):", socketError);
|
|
17170
|
+
const attachments = await collectAttachmentUploads({
|
|
17171
|
+
takeReplay: (sessionReplay == null ? void 0 : sessionReplay.canAttach) ? () => sessionReplay.takeSnapshot() : void 0,
|
|
17172
|
+
getConnections: () => getCollectorSession().socket.getConnections(),
|
|
17173
|
+
onError: (kind, error) => devLogger.error(
|
|
17174
|
+
"useIssueSubmission",
|
|
17175
|
+
kind === "replay" ? "세션 리플레이 스냅샷 실패 (이슈 생성 계속):" : "소켓 전사 직렬화 실패 (이슈 생성 계속):",
|
|
17176
|
+
error
|
|
17177
|
+
)
|
|
17178
|
+
});
|
|
17179
|
+
if (hasReplayUpload(attachments)) {
|
|
17180
|
+
issueData.session_replay_pending = true;
|
|
16952
17181
|
}
|
|
16953
17182
|
const { networkLogs: fittedNetworkLogs, stillOverBudget } = shrinkNetworkLogsToFit(
|
|
16954
17183
|
issueData.network_logs ?? [],
|
|
@@ -16967,6 +17196,16 @@ function useIssueSubmission({
|
|
|
16967
17196
|
notionProperties: data.notionFields
|
|
16968
17197
|
});
|
|
16969
17198
|
const createdIssue = await issueService.createIssue({ ...issueData, integrations });
|
|
17199
|
+
if (videoFile2 || attachments.length > 0) {
|
|
17200
|
+
await enqueueIssueUploads({
|
|
17201
|
+
videoQueue: getWidgetVideoUploadQueue(),
|
|
17202
|
+
attachmentQueue: getWidgetAttachmentUploadQueue(),
|
|
17203
|
+
issueId: createdIssue.id,
|
|
17204
|
+
projectKey: authInfo.projectId,
|
|
17205
|
+
video: videoFile2 ? { blob: videoFile2, mimeType: normalizeUploadMimeType(videoFile2.type, "video") } : null,
|
|
17206
|
+
attachments
|
|
17207
|
+
});
|
|
17208
|
+
}
|
|
16970
17209
|
for (const service of createdIssue.failed_services ?? []) {
|
|
16971
17210
|
toast.error(getIntegrationFailureMessage(service));
|
|
16972
17211
|
}
|
|
@@ -17608,6 +17847,7 @@ function IssueFormError({ error }) {
|
|
|
17608
17847
|
return /* @__PURE__ */ jsx("div", { className: "rounded-[18px] border border-danger/20 bg-danger-subtle px-4 py-3 text-sm text-danger", children: error });
|
|
17609
17848
|
}
|
|
17610
17849
|
const SWITCH_TO_AI = "AI 작성으로 돌아가기";
|
|
17850
|
+
const SWITCH_TO_AI_HINT = "기대한 동작만 적으면 AI가 제목과 설명을 작성합니다.";
|
|
17611
17851
|
function IssueFormHeader({ title, onClose, onSwitchToAi }) {
|
|
17612
17852
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
17613
17853
|
/* @__PURE__ */ jsx("h2", { className: "m-0 text-lg font-semibold text-text-primary", children: title }),
|
|
@@ -17624,7 +17864,10 @@ function IssueFormHeader({ title, onClose, onSwitchToAi }) {
|
|
|
17624
17864
|
children: /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4" })
|
|
17625
17865
|
}
|
|
17626
17866
|
) }),
|
|
17627
|
-
/* @__PURE__ */
|
|
17867
|
+
/* @__PURE__ */ jsxs(TooltipContent, { side: "top", sideOffset: 10, className: "max-w-[16rem]", children: [
|
|
17868
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium", children: SWITCH_TO_AI }),
|
|
17869
|
+
/* @__PURE__ */ jsx("p", { className: "mt-0.5 opacity-80", children: SWITCH_TO_AI_HINT })
|
|
17870
|
+
] })
|
|
17628
17871
|
] }) }) : null,
|
|
17629
17872
|
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: onClose, "aria-label": "닫기", children: /* @__PURE__ */ jsx(X$1, { className: "h-4 w-4" }) })
|
|
17630
17873
|
] })
|
|
@@ -18175,18 +18418,6 @@ function IssueForm({
|
|
|
18175
18418
|
getPortalContainer()
|
|
18176
18419
|
);
|
|
18177
18420
|
}
|
|
18178
|
-
function invalidateIssueQueries(issueId) {
|
|
18179
|
-
issueService.invalidateCache();
|
|
18180
|
-
queryClient.invalidateQueries({ queryKey: ["contentIssues"] });
|
|
18181
|
-
queryClient.invalidateQueries({ queryKey: ["issue", issueId] });
|
|
18182
|
-
}
|
|
18183
|
-
function notifyIssueUpdated(issueId) {
|
|
18184
|
-
SDKManager.getInstance().eventBus.emit("issue:updated", issueId);
|
|
18185
|
-
}
|
|
18186
|
-
function applyIssueMutationEffects(issueId) {
|
|
18187
|
-
invalidateIssueQueries(issueId);
|
|
18188
|
-
notifyIssueUpdated(issueId);
|
|
18189
|
-
}
|
|
18190
18421
|
function useJiraIssueSync(issue) {
|
|
18191
18422
|
const [isSyncingAll, setIsSyncingAll] = useState(false);
|
|
18192
18423
|
const mapping = getPrimaryJiraMapping(issue);
|
|
@@ -18770,12 +19001,13 @@ function ResizableSplitPane({
|
|
|
18770
19001
|
var _a;
|
|
18771
19002
|
event.preventDefault();
|
|
18772
19003
|
(_a = dragCleanupRef.current) == null ? void 0 : _a.call(dragCleanupRef);
|
|
19004
|
+
const releaseScopes = /* @__PURE__ */ new Set([document, event.currentTarget.getRootNode()]);
|
|
18773
19005
|
const handleDocumentMouseMove = (moveEvent) => {
|
|
18774
19006
|
updateRatio(moveEvent.clientX);
|
|
18775
19007
|
};
|
|
18776
19008
|
const stopDragging = () => {
|
|
18777
19009
|
document.removeEventListener("mousemove", handleDocumentMouseMove);
|
|
18778
|
-
|
|
19010
|
+
releaseScopes.forEach((scope) => scope.removeEventListener("mouseup", stopDragging));
|
|
18779
19011
|
window.removeEventListener("blur", stopDragging);
|
|
18780
19012
|
if (dragCleanupRef.current === stopDragging) {
|
|
18781
19013
|
dragCleanupRef.current = null;
|
|
@@ -18783,7 +19015,7 @@ function ResizableSplitPane({
|
|
|
18783
19015
|
};
|
|
18784
19016
|
dragCleanupRef.current = stopDragging;
|
|
18785
19017
|
document.addEventListener("mousemove", handleDocumentMouseMove);
|
|
18786
|
-
|
|
19018
|
+
releaseScopes.forEach((scope) => scope.addEventListener("mouseup", stopDragging));
|
|
18787
19019
|
window.addEventListener("blur", stopDragging);
|
|
18788
19020
|
},
|
|
18789
19021
|
[updateRatio]
|
|
@@ -21232,9 +21464,6 @@ const svg = merge([aria, svg$1, xlink, xmlns, xml], "svg");
|
|
|
21232
21464
|
function stringify(values) {
|
|
21233
21465
|
return values.join(" ").trim();
|
|
21234
21466
|
}
|
|
21235
|
-
function getDefaultExportFromCjs(x) {
|
|
21236
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
21237
|
-
}
|
|
21238
21467
|
var cjs$2 = {};
|
|
21239
21468
|
var cjs$1;
|
|
21240
21469
|
var hasRequiredCjs$2;
|
|
@@ -34839,9 +35068,20 @@ const markdownComponents = {
|
|
|
34839
35068
|
h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "my-3 whitespace-pre-wrap text-lg font-semibold text-text-primary", children }),
|
|
34840
35069
|
h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "my-2.5 whitespace-pre-wrap text-base font-semibold text-text-primary", children }),
|
|
34841
35070
|
p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "my-2 whitespace-pre-wrap text-text-primary", children }),
|
|
34842
|
-
|
|
35071
|
+
// 노션 할 일 블록은 GFM 작업 목록(`- [ ]`)으로 들어온다. 글머리표 대신 체크박스가 그 자리를 맡는다.
|
|
35072
|
+
ul: ({ children, className }) => (className == null ? void 0 : className.includes("contains-task-list")) ? /* @__PURE__ */ jsx("ul", { className: "my-2 list-none pl-0 text-text-primary [li_&]:pl-5", children }) : /* @__PURE__ */ jsx("ul", { className: "my-2 list-disc pl-5 text-text-primary", children }),
|
|
34843
35073
|
ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "my-2 list-decimal pl-5 text-text-primary", children }),
|
|
34844
35074
|
li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "my-1", children }),
|
|
35075
|
+
input: ({ type, checked }) => type === "checkbox" ? /* @__PURE__ */ jsx(
|
|
35076
|
+
"input",
|
|
35077
|
+
{
|
|
35078
|
+
type: "checkbox",
|
|
35079
|
+
checked,
|
|
35080
|
+
disabled: true,
|
|
35081
|
+
readOnly: true,
|
|
35082
|
+
className: "mr-2 align-middle accent-brand"
|
|
35083
|
+
}
|
|
35084
|
+
) : null,
|
|
34845
35085
|
code: ({ children, className }) => {
|
|
34846
35086
|
const isInline = !className;
|
|
34847
35087
|
if (isInline) {
|
|
@@ -34858,7 +35098,8 @@ const markdownComponents = {
|
|
|
34858
35098
|
// 깊이만큼 밀린다.
|
|
34859
35099
|
details: ({ children }) => /* @__PURE__ */ jsx("details", { className: "my-2 [&>*:not(summary)]:pl-4", children }),
|
|
34860
35100
|
summary: ({ children }) => /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-text-primary marker:text-text-tertiary", children }),
|
|
34861
|
-
|
|
35101
|
+
// 노션의 빈 파일·PDF 블록은 `[pdf]()` 로 들어온다. 빈 href 는 현재 페이지로 이동하므로 글자로만 둔다.
|
|
35102
|
+
a: ({ href, children }) => href ? /* @__PURE__ */ jsx(
|
|
34862
35103
|
"a",
|
|
34863
35104
|
{
|
|
34864
35105
|
href,
|
|
@@ -34867,7 +35108,7 @@ const markdownComponents = {
|
|
|
34867
35108
|
className: "text-brand underline underline-offset-2 hover:text-brand-hover",
|
|
34868
35109
|
children
|
|
34869
35110
|
}
|
|
34870
|
-
),
|
|
35111
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-text-secondary", children }),
|
|
34871
35112
|
blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { className: "my-2 border-l-4 border-line-strong pl-3 italic text-text-secondary", children }),
|
|
34872
35113
|
hr: () => /* @__PURE__ */ jsx("hr", { className: "my-4 border-0 border-t border-line" }),
|
|
34873
35114
|
strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: "font-semibold", children }),
|
|
@@ -35354,6 +35595,10 @@ function ImageViewer({
|
|
|
35354
35595
|
title = "이미지 전체화면 보기"
|
|
35355
35596
|
}) {
|
|
35356
35597
|
const portalContainer = usePortalContainer();
|
|
35598
|
+
const dismissRef = useShadowOutsideDismiss(
|
|
35599
|
+
useCallback(() => onOpenChange(false), [onOpenChange]),
|
|
35600
|
+
{ focusOutside: false }
|
|
35601
|
+
);
|
|
35357
35602
|
return /* @__PURE__ */ jsx(Dialog$1, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogPortal$1, { container: portalContainer, children: [
|
|
35358
35603
|
/* @__PURE__ */ jsx(
|
|
35359
35604
|
DialogOverlay$1,
|
|
@@ -35368,6 +35613,7 @@ function ImageViewer({
|
|
|
35368
35613
|
/* @__PURE__ */ jsxs(
|
|
35369
35614
|
DialogContent$1,
|
|
35370
35615
|
{
|
|
35616
|
+
ref: dismissRef,
|
|
35371
35617
|
onEscapeKeyDown: stopEscapePropagation(),
|
|
35372
35618
|
style: {
|
|
35373
35619
|
left: `calc(50% - (var(${BODY_SCROLLBAR_WIDTH_CSS_VAR}, 0px) / 2))`
|
|
@@ -35405,6 +35651,11 @@ function ImageViewer({
|
|
|
35405
35651
|
)
|
|
35406
35652
|
] }) });
|
|
35407
35653
|
}
|
|
35654
|
+
function orderScreenshotsForDisplay(urls) {
|
|
35655
|
+
if (urls.length !== 2) return [...urls];
|
|
35656
|
+
const [full, element2] = urls;
|
|
35657
|
+
return [element2, full];
|
|
35658
|
+
}
|
|
35408
35659
|
function parseScreenshotUrls(screenshot) {
|
|
35409
35660
|
if (Array.isArray(screenshot)) {
|
|
35410
35661
|
return screenshot.filter((url) => typeof url === "string" && url.length > 0);
|
|
@@ -35427,7 +35678,7 @@ function parseScreenshotUrls(screenshot) {
|
|
|
35427
35678
|
return [screenshot];
|
|
35428
35679
|
}
|
|
35429
35680
|
function IssueScreenshot({ screenshot }) {
|
|
35430
|
-
const screenshotUrls = parseScreenshotUrls(screenshot);
|
|
35681
|
+
const screenshotUrls = orderScreenshotsForDisplay(parseScreenshotUrls(screenshot));
|
|
35431
35682
|
const [selectedImageUrl, setSelectedImageUrl] = useState(
|
|
35432
35683
|
screenshotUrls[0] ?? null
|
|
35433
35684
|
);
|
|
@@ -37839,6 +38090,7 @@ function IssueStickersContainer$1({
|
|
|
37839
38090
|
[clearClosingCluster, collapseExpandedCluster, expandedClusterId]
|
|
37840
38091
|
);
|
|
37841
38092
|
useEffect(() => {
|
|
38093
|
+
var _a;
|
|
37842
38094
|
if (!expandedClusterId) return void 0;
|
|
37843
38095
|
const handlePointerDown = (event) => {
|
|
37844
38096
|
const root2 = rootRef.current;
|
|
@@ -37847,8 +38099,9 @@ function IssueStickersContainer$1({
|
|
|
37847
38099
|
collapseExpandedCluster();
|
|
37848
38100
|
}
|
|
37849
38101
|
};
|
|
37850
|
-
document.
|
|
37851
|
-
|
|
38102
|
+
const scopes = /* @__PURE__ */ new Set([document, ((_a = rootRef.current) == null ? void 0 : _a.getRootNode()) ?? document]);
|
|
38103
|
+
scopes.forEach((scope) => scope.addEventListener("pointerdown", handlePointerDown, true));
|
|
38104
|
+
return () => scopes.forEach((scope) => scope.removeEventListener("pointerdown", handlePointerDown, true));
|
|
37852
38105
|
}, [collapseExpandedCluster, expandedClusterId]);
|
|
37853
38106
|
if (!visible) {
|
|
37854
38107
|
return null;
|
|
@@ -38112,6 +38365,9 @@ function useKeyboardShortcuts(isCreatingIssueRef, onToggleIssueMode, onToggleRec
|
|
|
38112
38365
|
return;
|
|
38113
38366
|
}
|
|
38114
38367
|
if (isRecordingShortcut(eventLike)) {
|
|
38368
|
+
if (isIssueFormOpen) {
|
|
38369
|
+
return;
|
|
38370
|
+
}
|
|
38115
38371
|
e.preventDefault();
|
|
38116
38372
|
e.stopPropagation();
|
|
38117
38373
|
if (isProcessingRecordingRef.current) {
|
|
@@ -38439,15 +38695,16 @@ function useContentAppState() {
|
|
|
38439
38695
|
}, [isCreatingIssue]);
|
|
38440
38696
|
const handleIssueCreated = useCallback(
|
|
38441
38697
|
async (hasIntegrationFailure = false) => {
|
|
38698
|
+
const hadVideo = Boolean(clickPosition == null ? void 0 : clickPosition.videoFile);
|
|
38442
38699
|
clearClickPosition();
|
|
38443
38700
|
screenRecording.clearRecordedFile();
|
|
38444
38701
|
await loadIssues();
|
|
38445
38702
|
await toggleIssueMode(false);
|
|
38446
38703
|
if (!hasIntegrationFailure) {
|
|
38447
|
-
showToast("이슈가 생성되었습니다.");
|
|
38704
|
+
showToast(hadVideo ? VIDEO_UPLOAD_COPY.created : "이슈가 생성되었습니다.");
|
|
38448
38705
|
}
|
|
38449
38706
|
},
|
|
38450
|
-
[clearClickPosition, loadIssues, screenRecording, toggleIssueMode, showToast]
|
|
38707
|
+
[clickPosition, clearClickPosition, loadIssues, screenRecording, toggleIssueMode, showToast]
|
|
38451
38708
|
);
|
|
38452
38709
|
return {
|
|
38453
38710
|
// 상태
|
|
@@ -38476,6 +38733,31 @@ function useContentAppState() {
|
|
|
38476
38733
|
setFieldFilters
|
|
38477
38734
|
};
|
|
38478
38735
|
}
|
|
38736
|
+
function useWidgetVideoUploads(projectId) {
|
|
38737
|
+
const [states, setStates] = useState([]);
|
|
38738
|
+
useEffect(() => getWidgetVideoUploadQueue().subscribe(setStates), []);
|
|
38739
|
+
useEffect(() => {
|
|
38740
|
+
if (!projectId) return;
|
|
38741
|
+
void resumeWidgetIssueUploads(projectId).then((count) => {
|
|
38742
|
+
if (count > 0) toast.info(VIDEO_UPLOAD_COPY.resumed(count));
|
|
38743
|
+
void getWidgetVideoUploadQueue().pruneExpired();
|
|
38744
|
+
void getWidgetAttachmentUploadQueue().pruneExpired();
|
|
38745
|
+
});
|
|
38746
|
+
}, [projectId]);
|
|
38747
|
+
useEffect(() => {
|
|
38748
|
+
const handleBeforeUnload = (event) => {
|
|
38749
|
+
if (getWidgetVideoUploadQueue().hasActiveUploads() || getWidgetAttachmentUploadQueue().hasActiveUploads()) {
|
|
38750
|
+
event.preventDefault();
|
|
38751
|
+
}
|
|
38752
|
+
};
|
|
38753
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
38754
|
+
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
38755
|
+
}, []);
|
|
38756
|
+
const retryFailedUploads = () => {
|
|
38757
|
+
states.filter((state) => state.status === "failed").forEach((state) => retryWidgetIssueUploads(state.issueId));
|
|
38758
|
+
};
|
|
38759
|
+
return { uploadProgress: summarizeVideoUploads(states), retryFailedUploads };
|
|
38760
|
+
}
|
|
38479
38761
|
const STORAGE_KEY = "issue-sticker-sticker-render-mode";
|
|
38480
38762
|
const QUERY_ROOT = ["stickerRenderMode"];
|
|
38481
38763
|
function readLocalRenderMode() {
|
|
@@ -38841,7 +39123,7 @@ function MoreMenu({
|
|
|
38841
39123
|
},
|
|
38842
39124
|
{
|
|
38843
39125
|
id: "unrendered",
|
|
38844
|
-
label: unrenderedStickerCount > 0 ?
|
|
39126
|
+
label: unrenderedStickerCount > 0 ? `표시하지 못한 스티커 ${unrenderedStickerCount}개` : "표시하지 못한 스티커 없음",
|
|
38845
39127
|
icon: /* @__PURE__ */ jsx(CircleAlert, { size: ICON_SIZE }),
|
|
38846
39128
|
onClick: onOpenUnrenderedStickers,
|
|
38847
39129
|
// 0개일 때도 노출한다. 숨기면 목록을 열어 확인할 진입점 자체가 없어진다.
|
|
@@ -39086,6 +39368,35 @@ const TOOLBAR_STYLES = `
|
|
|
39086
39368
|
border: 2px solid hsl(var(--surface-1));
|
|
39087
39369
|
pointer-events: none;
|
|
39088
39370
|
}
|
|
39371
|
+
.toolbar-upload {
|
|
39372
|
+
width: 34px;
|
|
39373
|
+
height: 34px;
|
|
39374
|
+
display: flex;
|
|
39375
|
+
align-items: center;
|
|
39376
|
+
justify-content: center;
|
|
39377
|
+
flex: none;
|
|
39378
|
+
border-radius: 50%;
|
|
39379
|
+
border: none;
|
|
39380
|
+
background: transparent;
|
|
39381
|
+
padding: 0;
|
|
39382
|
+
outline: none;
|
|
39383
|
+
}
|
|
39384
|
+
button.toolbar-upload { cursor: pointer; }
|
|
39385
|
+
.toolbar-upload:focus-visible { box-shadow: var(--shadow-focus); }
|
|
39386
|
+
.toolbar-upload svg { transform: rotate(-90deg); }
|
|
39387
|
+
.toolbar-upload-track {
|
|
39388
|
+
fill: none;
|
|
39389
|
+
stroke: hsl(var(--border-subtle));
|
|
39390
|
+
stroke-width: 2.5;
|
|
39391
|
+
}
|
|
39392
|
+
.toolbar-upload-bar {
|
|
39393
|
+
fill: none;
|
|
39394
|
+
stroke: var(--brand);
|
|
39395
|
+
stroke-width: 2.5;
|
|
39396
|
+
stroke-linecap: round;
|
|
39397
|
+
transition: stroke-dashoffset 0.3s ease;
|
|
39398
|
+
}
|
|
39399
|
+
.toolbar-upload[data-failed="true"] .toolbar-upload-bar { stroke: hsl(var(--danger)); }
|
|
39089
39400
|
|
|
39090
39401
|
.toolbar-menu {
|
|
39091
39402
|
position: absolute;
|
|
@@ -39363,6 +39674,13 @@ function formatElapsed(startedAt, now2) {
|
|
|
39363
39674
|
const ss = String(seconds % 60).padStart(2, "0");
|
|
39364
39675
|
return `${mm}:${ss}`;
|
|
39365
39676
|
}
|
|
39677
|
+
const UPLOAD_RING_RADIUS = 7;
|
|
39678
|
+
const UPLOAD_RING_LENGTH = 2 * Math.PI * UPLOAD_RING_RADIUS;
|
|
39679
|
+
function formatUploadLabel({ percent: percent2, count, failed }) {
|
|
39680
|
+
if (failed) return "영상 업로드 실패";
|
|
39681
|
+
const waiting = count > 1 ? ` · 대기 ${count - 1}개` : "";
|
|
39682
|
+
return `영상 업로드 중 ${percent2}%${waiting}`;
|
|
39683
|
+
}
|
|
39366
39684
|
function Toolbar({
|
|
39367
39685
|
onCreateIssue,
|
|
39368
39686
|
onToggleStickers,
|
|
@@ -39384,7 +39702,9 @@ function Toolbar({
|
|
|
39384
39702
|
targets,
|
|
39385
39703
|
account,
|
|
39386
39704
|
blocked,
|
|
39387
|
-
filter: filter2
|
|
39705
|
+
filter: filter2,
|
|
39706
|
+
uploadProgress,
|
|
39707
|
+
onUploadRetry
|
|
39388
39708
|
}) {
|
|
39389
39709
|
const rootRef = useRef(null);
|
|
39390
39710
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
@@ -39488,6 +39808,20 @@ function Toolbar({
|
|
|
39488
39808
|
}, []);
|
|
39489
39809
|
const anchor = toCssAnchor(placement);
|
|
39490
39810
|
const menuPlacement = getMenuPlacement(placement);
|
|
39811
|
+
const uploadRing = uploadProgress ? /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 18 18", "aria-hidden": "true", children: [
|
|
39812
|
+
/* @__PURE__ */ jsx("circle", { className: "toolbar-upload-track", cx: "9", cy: "9", r: UPLOAD_RING_RADIUS }),
|
|
39813
|
+
/* @__PURE__ */ jsx(
|
|
39814
|
+
"circle",
|
|
39815
|
+
{
|
|
39816
|
+
className: "toolbar-upload-bar",
|
|
39817
|
+
cx: "9",
|
|
39818
|
+
cy: "9",
|
|
39819
|
+
r: UPLOAD_RING_RADIUS,
|
|
39820
|
+
strokeDasharray: UPLOAD_RING_LENGTH,
|
|
39821
|
+
strokeDashoffset: uploadProgress.failed ? 0 : UPLOAD_RING_LENGTH * (1 - uploadProgress.percent / 100)
|
|
39822
|
+
}
|
|
39823
|
+
)
|
|
39824
|
+
] }) : null;
|
|
39491
39825
|
const idleBody = /* @__PURE__ */ jsxs(TooltipProvider, { delayDuration: 240, skipDelayDuration: 120, disableHoverableContent: true, children: [
|
|
39492
39826
|
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
39493
39827
|
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
@@ -39526,6 +39860,30 @@ function Toolbar({
|
|
|
39526
39860
|
/* @__PURE__ */ jsx("span", { className: "block font-normal opacity-70", children: "공유할 화면을 선택하는 창이 열립니다" })
|
|
39527
39861
|
] })
|
|
39528
39862
|
] }),
|
|
39863
|
+
uploadProgress ? /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
39864
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: uploadProgress.failed && onUploadRetry ? /* @__PURE__ */ jsx(
|
|
39865
|
+
"button",
|
|
39866
|
+
{
|
|
39867
|
+
type: "button",
|
|
39868
|
+
className: "toolbar-upload",
|
|
39869
|
+
"aria-label": ISSUE_UPLOAD_COPY.retry,
|
|
39870
|
+
"data-failed": true,
|
|
39871
|
+
onClick: onUploadRetry,
|
|
39872
|
+
children: uploadRing
|
|
39873
|
+
}
|
|
39874
|
+
) : /* @__PURE__ */ jsx(
|
|
39875
|
+
"span",
|
|
39876
|
+
{
|
|
39877
|
+
className: "toolbar-upload",
|
|
39878
|
+
role: "status",
|
|
39879
|
+
"aria-label": formatUploadLabel(uploadProgress),
|
|
39880
|
+
"data-failed": uploadProgress.failed,
|
|
39881
|
+
tabIndex: 0,
|
|
39882
|
+
children: uploadRing
|
|
39883
|
+
}
|
|
39884
|
+
) }),
|
|
39885
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "top", sideOffset: 10, children: formatUploadLabel(uploadProgress) })
|
|
39886
|
+
] }) : null,
|
|
39529
39887
|
/* @__PURE__ */ jsx("div", { className: "toolbar-divider" }),
|
|
39530
39888
|
/* @__PURE__ */ jsxs(
|
|
39531
39889
|
"button",
|
|
@@ -39577,7 +39935,7 @@ function Toolbar({
|
|
|
39577
39935
|
children: /* @__PURE__ */ jsx(X$1, { size: 15 })
|
|
39578
39936
|
}
|
|
39579
39937
|
)
|
|
39580
|
-
] }) : state === "
|
|
39938
|
+
] }) : state === "recording" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39581
39939
|
/* @__PURE__ */ jsx("span", { className: "toolbar-pulse", "aria-hidden": "true" }),
|
|
39582
39940
|
/* @__PURE__ */ jsx("span", { className: "toolbar-elapsed", "aria-hidden": "true", children: formatElapsed(recordingStartedAt, now2) }),
|
|
39583
39941
|
/* @__PURE__ */ jsx("div", { className: "toolbar-divider" }),
|
|
@@ -39592,6 +39950,7 @@ function Toolbar({
|
|
|
39592
39950
|
}
|
|
39593
39951
|
)
|
|
39594
39952
|
] }) : idleBody;
|
|
39953
|
+
if (state === "writing") return null;
|
|
39595
39954
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39596
39955
|
/* @__PURE__ */ jsx("style", { children: TOOLBAR_STYLES }),
|
|
39597
39956
|
/* @__PURE__ */ jsxs(Popover, { open: filterOpen, onOpenChange: setFilterOpen, children: [
|
|
@@ -39747,6 +40106,7 @@ function ContentAppWrapper({
|
|
|
39747
40106
|
const { renderMode, saveRenderMode } = useStickerRenderMode();
|
|
39748
40107
|
const { isMember } = useAuthContext();
|
|
39749
40108
|
const { selectedProjectId } = useProject();
|
|
40109
|
+
const { uploadProgress, retryFailedUploads } = useWidgetVideoUploads(selectedProjectId);
|
|
39750
40110
|
const filterProjectId = isMember ? selectedProjectId : null;
|
|
39751
40111
|
const { data: filterGroups = [] } = useQuery({
|
|
39752
40112
|
queryKey: ["issueFilterGroups", filterProjectId],
|
|
@@ -39789,6 +40149,8 @@ function ContentAppWrapper({
|
|
|
39789
40149
|
recordingStartedAt: screenRecording.startedAt,
|
|
39790
40150
|
showStickers,
|
|
39791
40151
|
toolbar,
|
|
40152
|
+
uploadProgress,
|
|
40153
|
+
onUploadRetry: retryFailedUploads,
|
|
39792
40154
|
stickerRenderMode: renderMode,
|
|
39793
40155
|
onToggleStickerRenderMode: () => void saveRenderMode(nextRenderMode),
|
|
39794
40156
|
unrenderedStickerCount: unrenderedCount,
|
|
@@ -39884,12 +40246,13 @@ function AuthGate() {
|
|
|
39884
40246
|
) })
|
|
39885
40247
|
] });
|
|
39886
40248
|
}
|
|
39887
|
-
const globalsCSS = `:root,:host{color-scheme:light;--brand-h: 150;--brand-s: 100%;--brand-l: 34%;--brand-hsl: var(--brand-h) var(--brand-s) var(--brand-l);--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) calc(var(--brand-s) + 3%) calc(var(--brand-l) - 4%));--brand-active: hsl(var(--brand-h) calc(var(--brand-s) + 2%) calc(var(--brand-l) - 8%));--brand-subtle: hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14);--brand-border: hsl(var(--brand-h) calc(var(--brand-s) + 8%) calc(var(--brand-l) + 8%) / .34);--brand-fg: hsl(0 0% 100%);--brand-ring: hsl(var(--brand-h) calc(var(--brand-s) + 12%) calc(var(--brand-l) + 10%) / .22);--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-display: var(--font-sans);--font-mono: var(--font-sans);--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--text-disabled: 145 4% 70%;--text-inverse: 0 0% 100%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--border-focus: var(--brand-h) var(--brand-s) var(--brand-l);--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 52%;--warning-subtle: 34 82% 52% / .14;--danger: 3 68% 56%;--danger-subtle: 3 68% 56% / .12;--danger-deep: 3 62% 40%;--info: 202 52% 44%;--info-subtle: 202 52% 44% / .12;--accent-terra: 13 52% 47%;--accent-terra-subtle: 13 52% 47% / .1;--accent-terra-deep: 13 48% 44%;--accent-blue: 213 86% 56%;--accent-blue-subtle: 213 92% 56% / .12;--accent-blue-deep: 216 78% 40%;--accent-blue-border: 213 86% 62% / .36;--accent-cream: 38 52% 88%;--accent-cream-warm: 40 56% 95%;--accent-cream-deep: 38 48% 82%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 11%;--radius-xs: 4px;--radius-sm: 8px;--radius-md: 12px;--radius-lg: 16px;--radius-xl: 20px;--radius-2xl: 24px;--radius-pill: 9999px;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 3px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 14%) / .24), 0 6px 20px hsl(var(--brand-h) calc(var(--brand-s) - 70%) calc(var(--brand-l) - 19%) / .16);--duration-instant: 90ms;--duration-fast: .16s;--duration-base: .26s;--duration-out: .18s;--duration-slow: .36s;--ease-out: cubic-bezier(.23, 1, .32, 1);--ease-in-out: cubic-bezier(.45, 0, .15, 1);--ease-spring: cubic-bezier(.18, .94, .32, 1.08);--grid-line: 0 0% 92%}.dark,:host(.dark){color-scheme:dark;--brand-l: 34%;--brand-fg: hsl(0 0% 100%);--surface-0: 150 8% 7%;--surface-1: 150 6% 10%;--surface-2: 150 5% 14%;--surface-3: 150 4% 18%;--surface-inset: 150 6% 6%;--overlay-backdrop: hsl(0 0% 0% / .56);--overlay-backdrop-strong: hsl(0 0% 0% / .8);--text-primary: 40 16% 93%;--text-secondary: 36 8% 68%;--text-tertiary: 34 6% 50%;--text-disabled: 30 5% 34%;--text-inverse: 150 8% 10%;--border-subtle: 150 6% 16%;--border-default: 150 5% 22%;--border-strong: 150 4% 34%;--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 62%;--danger: 2 70% 64%;--danger-deep: 2 80% 76%;--info: 202 54% 62%;--accent-terra: 13 56% 62%;--accent-terra-subtle: 13 56% 62% / .14;--accent-terra-deep: 13 52% 56%;--accent-blue: 210 92% 68%;--accent-blue-subtle: 210 92% 68% / .18;--accent-blue-deep: 209 100% 78%;--accent-blue-border: 210 92% 72% / .44;--accent-cream: 38 30% 26%;--accent-cream-warm: 38 22% 18%;--accent-cream-deep: 38 26% 32%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 8%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .2);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .3), 0 1px 2px -1px hsl(0 0% 0% / .24);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .34), 0 2px 4px -2px hsl(0 0% 0% / .2);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .38), 0 4px 6px -4px hsl(0 0% 0% / .24);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .44), 0 8px 10px -6px hsl(0 0% 0% / .28);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .16);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 24%) / .44), 0 6px 20px hsl(0 0% 0% / .32);--grid-line: 150 6% 14%}*{border-color:hsl(var(--border-default))}html{font-family:var(--font-sans),ui-sans-serif,system-ui,-apple-system,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-feature-settings:"cv11","ss01","ss03";background-color:hsl(var(--surface-0))}body{margin:0;min-height:100vh;color:hsl(var(--text-primary));background-color:hsl(var(--surface-0))}::-moz-selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}::selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:"ss01","ss02","cv11"}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:hsl(var(--border-strong) / .52);border-radius:var(--radius-pill);border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:hsl(var(--border-strong) / .9);background-clip:padding-box;border:2px solid transparent}.app-canvas,.grid-canvas{background-color:hsl(var(--surface-0))}.onboarding-canvas{word-break:keep-all;overflow-wrap:break-word;--surface-0: var(--brand-h) var(--brand-s) var(--brand-l);--surface-1: 0 0% 100%;--surface-2: var(--brand-h) 62% 28%;--surface-3: var(--brand-h) 60% 25%;--surface-inset: var(--brand-h) 62% 28%;--text-primary: 0 0% 100%;--text-secondary: var(--brand-h) 46% 90%;--text-tertiary: var(--brand-h) 34% 84%;--text-disabled: var(--brand-h) 20% 72%;--border-subtle: var(--brand-h) 44% 52%;--border-default: var(--brand-h) 40% 58%;--border-strong: var(--brand-h) 36% 70%;--border-focus: 0 0% 100%;--brand-hsl: 0 0% 100%;--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) 24% 94%);--brand-active: hsl(var(--brand-h) 20% 88%);--brand-fg: hsl(var(--brand-h) var(--brand-s) 24%);--brand-ring: hsl(0 0% 100% / .4);--danger: 6 96% 86%;--danger-subtle: 6 96% 86% / .18;--danger-deep: 6 96% 92%;--warning: 42 96% 82%;--warning-subtle: 42 96% 82% / .18}.onboarding-canvas .bg-surface-1,.onboarding-canvas input,.onboarding-canvas textarea,.onboarding-canvas [role=combobox]{--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--surface-2: 144 8% 96%;--surface-inset: 144 6% 95%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--brand-hsl: var(--brand-h) var(--brand-s) var(--brand-l);--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) calc(var(--brand-s) + 3%) calc(var(--brand-l) - 4%));--brand-active: hsl(var(--brand-h) calc(var(--brand-s) + 2%) calc(var(--brand-l) - 8%));--brand-fg: hsl(0 0% 100%);--brand-ring: hsl(var(--brand-h) calc(var(--brand-s) + 12%) calc(var(--brand-l) + 10%) / .22);--warning: 34 82% 52%;--warning-subtle: 34 82% 52% / .14;--danger: 3 68% 56%;--danger-subtle: 3 68% 56% / .12;--danger-deep: 3 62% 40%}@keyframes onboarding-step-in{0%{opacity:0;transform:translate(96px)}to{opacity:1;transform:translate(0)}}.onboarding-step-in{animation:onboarding-step-in var(--duration-slow) var(--ease-out) forwards}@keyframes onboarding-enter-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.onboarding-enter{position:fixed;top:0;right:0;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;animation:onboarding-enter-up var(--duration-base) var(--ease-out) forwards}body:has(.onboarding-canvas){background-color:hsl(var(--brand-h) var(--brand-s) var(--brand-l))}.panel-shell,.surface-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-sm)}.panel-shell-muted,.surface-shell-muted{background:hsl(var(--surface-2));box-shadow:var(--shadow-xs)}.panel-shell-subtle{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.panel-shell-elevated{border:1px solid hsl(var(--border-default));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.utility-chip,.floating-chip{display:inline-flex;align-items:center;gap:8px;border:1px solid hsl(var(--border-default));border-radius:var(--radius-pill);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.hairline{border-bottom:1px solid hsl(var(--border-subtle))}.mono-label{font-family:var(--font-mono),ui-monospace,monospace;font-size:11px;text-transform:uppercase;color:hsl(var(--text-tertiary))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root,:host{--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-mono: var(--font-sans);--issue-marker-expand-duration: .52s;--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 52%;--text-disabled: 145 4% 70%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--grid-line: 0 0% 92%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 4px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04)}*{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}#issue-sticker-shadow-root{all:initial;display:block;background-color:transparent;--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1));font-family:var(--font-sans);line-height:1.5}.\\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\\!visible{visibility:visible!important}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-x-1{left:4px;right:4px}.inset-y-0{top:0;bottom:0}.-bottom-px{bottom:-1px}.bottom-0{bottom:0}.bottom-4{bottom:16px}.bottom-6{bottom:24px}.left-0{left:0}.left-1\\/2{left:50%}.left-2{left:8px}.left-4{left:16px}.left-\\[50\\%\\]{left:50%}.right-0{right:0}.right-2{right:8px}.right-3{right:12px}.right-4{right:16px}.right-5{right:20px}.right-6{right:24px}.top-0{top:0}.top-1{top:4px}.top-1\\/2{top:50%}.top-2{top:8px}.top-3{top:12px}.top-4{top:16px}.top-5{top:20px}.top-\\[50\\%\\]{top:50%}.top-\\[calc\\(\\(3\\.5rem-1\\.75rem\\)\\/2\\)\\]{top:14px}.top-full{top:100%}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-\\[1000000\\]{z-index:1000000}.z-\\[1000003\\]{z-index:1000003}.z-\\[1000004\\]{z-index:1000004}.z-\\[1000005\\]{z-index:1000005}.z-\\[1000006\\]{z-index:1000006}.z-\\[1000007\\]{z-index:1000007}.z-\\[1000008\\]{z-index:1000008}.z-\\[1000010\\]{z-index:1000010}.z-\\[1000011\\]{z-index:1000011}.z-\\[10001\\]{z-index:10001}.z-\\[999999\\]{z-index:999999}.z-\\[9999\\]{z-index:9999}.m-0{margin:0}.-mx-2{margin-left:-8px;margin-right:-8px}.mx-3{margin-left:12px;margin-right:12px}.my-1{margin-top:4px;margin-bottom:4px}.my-2{margin-top:8px;margin-bottom:8px}.my-2\\.5{margin-top:10px;margin-bottom:10px}.my-3{margin-top:12px;margin-bottom:12px}.my-4{margin-top:16px;margin-bottom:16px}.mb-0\\.5{margin-bottom:2px}.mb-1{margin-bottom:4px}.mb-2{margin-bottom:8px}.mb-3{margin-bottom:12px}.mb-5{margin-bottom:20px}.ml-0\\.5{margin-left:2px}.ml-4{margin-left:16px}.mr-1\\.5{margin-right:6px}.mt-0{margin-top:0}.mt-0\\.5{margin-top:2px}.mt-1{margin-top:4px}.mt-2{margin-top:8px}.mt-3{margin-top:12px}.mt-4{margin-top:16px}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.\\!h-auto{height:auto!important}.h-1\\.5{height:6px}.h-10{height:40px}.h-11{height:44px}.h-2{height:8px}.h-24{height:96px}.h-3{height:12px}.h-3\\.5{height:14px}.h-4{height:16px}.h-5{height:20px}.h-6{height:24px}.h-7{height:28px}.h-8{height:32px}.h-9{height:36px}.h-\\[1\\.4rem\\]{height:22.4px}.h-\\[100vh\\]{height:100vh}.h-\\[18px\\]{height:18px}.h-\\[220px\\]{height:220px}.h-\\[22px\\]{height:22px}.h-\\[30px\\]{height:30px}.h-\\[min\\(36vh\\,320px\\)\\]{height:min(36vh,320px)}.h-\\[min\\(480px\\,calc\\(100vh-64px\\)\\)\\]{height:min(480px,calc(100vh - 64px))}.h-\\[min\\(54vh\\,520px\\)\\]{height:min(54vh,520px)}.h-\\[min\\(560px\\,calc\\(100vh-32px\\)\\)\\]{height:min(560px,calc(100vh - 32px))}.h-\\[var\\(--issue-sticker-size\\)\\]{height:var(--issue-sticker-size)}.h-\\[var\\(--radix-select-trigger-height\\)\\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.max-h-24{max-height:96px}.max-h-40{max-height:160px}.max-h-56{max-height:224px}.max-h-80{max-height:320px}.max-h-96{max-height:384px}.max-h-\\[150px\\]{max-height:150px}.max-h-\\[220px\\]{max-height:220px}.max-h-\\[320px\\]{max-height:320px}.max-h-\\[420px\\]{max-height:420px}.max-h-\\[90vh\\]{max-height:90vh}.max-h-\\[calc\\(100vh-3rem\\)\\]{max-height:calc(100vh - 48px)}.max-h-\\[min\\(80vh\\,640px\\)\\]{max-height:min(80vh,640px)}.min-h-0{min-height:0px}.min-h-11{min-height:44px}.min-h-\\[108px\\]{min-height:108px}.min-h-\\[120px\\]{min-height:120px}.min-h-\\[140px\\]{min-height:140px}.min-h-\\[220px\\]{min-height:220px}.w-0\\.5{width:2px}.w-1{width:4px}.w-1\\.5{width:6px}.w-1\\/2{width:50%}.w-10{width:40px}.w-12{width:48px}.w-14{width:56px}.w-16{width:64px}.w-2{width:8px}.w-3{width:12px}.w-3\\.5{width:14px}.w-4{width:16px}.w-5{width:20px}.w-6{width:24px}.w-7{width:28px}.w-72{width:288px}.w-8{width:32px}.w-80{width:320px}.w-9{width:36px}.w-\\[1\\.4rem\\]{width:22.4px}.w-\\[18px\\]{width:18px}.w-\\[22\\.5rem\\]{width:360px}.w-\\[22rem\\]{width:352px}.w-\\[30px\\]{width:30px}.w-\\[38px\\]{width:38px}.w-\\[calc\\(100vw-32px\\)\\]{width:calc(100vw - 32px)}.w-\\[min\\(20rem\\,calc\\(100vw_-_1\\.5rem\\)\\)\\]{width:min(320px,calc(100vw - 24px))}.w-\\[min\\(560px\\,calc\\(100vw-32px\\)\\)\\]{width:min(560px,calc(100vw - 32px))}.w-\\[var\\(--radix-popover-trigger-width\\)\\]{width:var(--radix-popover-trigger-width)}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-0{min-width:0px}.min-w-9{min-width:36px}.min-w-\\[12rem\\]{min-width:192px}.min-w-\\[200px\\]{min-width:200px}.min-w-\\[var\\(--radix-popover-trigger-width\\)\\]{min-width:var(--radix-popover-trigger-width)}.min-w-\\[var\\(--radix-select-trigger-width\\)\\]{min-width:var(--radix-select-trigger-width)}.max-w-\\[10rem\\]{max-width:160px}.max-w-\\[120px\\]{max-width:120px}.max-w-\\[160px\\]{max-width:160px}.max-w-\\[260px\\]{max-width:260px}.max-w-\\[280px\\]{max-width:280px}.max-w-\\[28rem\\]{max-width:448px}.max-w-\\[300px\\]{max-width:300px}.max-w-\\[360px\\]{max-width:360px}.max-w-\\[36rem\\]{max-width:576px}.max-w-\\[400px\\]{max-width:400px}.max-w-\\[420px\\]{max-width:420px}.max-w-\\[428px\\]{max-width:428px}.max-w-\\[480px\\]{max-width:480px}.max-w-\\[62ch\\]{max-width:62ch}.max-w-\\[640px\\]{max-width:640px}.max-w-\\[70ch\\]{max-width:70ch}.max-w-\\[90vw\\]{max-width:90vw}.max-w-\\[960px\\]{max-width:960px}.max-w-\\[calc\\(100vw-24px\\)\\]{max-width:calc(100vw - 24px)}.max-w-\\[var\\(--issue-sticker-size\\)\\]{max-width:var(--issue-sticker-size)}.max-w-full{max-width:100%}.max-w-md{max-width:448px}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.-translate-x-1{--tw-translate-x: -4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1{--tw-translate-x: 4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[-50\\%\\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[18px\\]{--tw-translate-x: 18px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[2px\\]{--tw-translate-x: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\\[-50\\%\\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes pulse-ring{0%,to{box-shadow:0 0 0 0 var(--brand-ring)}50%{box-shadow:0 0 0 8px transparent}}.animate-pulse-ring{animation:pulse-ring 1.8s var(--ease-in-out) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\\.5{gap:2px}.gap-1{gap:4px}.gap-1\\.5{gap:6px}.gap-2{gap:8px}.gap-2\\.5{gap:10px}.gap-3{gap:12px}.gap-3\\.5{gap:14px}.gap-4{gap:16px}.gap-5{gap:20px}.gap-6{gap:24px}.gap-x-5{-moz-column-gap:20px;column-gap:20px}.gap-y-2{row-gap:8px}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(4px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(4px * var(--tw-space-y-reverse))}.space-y-1\\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(6px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(6px * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(8px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(8px * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(12px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(12px * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(16px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(16px * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(20px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(20px * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(24px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(24px * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-line-subtle>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.break-keep{word-break:keep-all}.\\!rounded-none{border-radius:0!important}.rounded{border-radius:4px}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[18px\\]{border-radius:18px}.rounded-\\[20px\\]{border-radius:20px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-xs{border-radius:var(--radius-xs)}.rounded-b-md{border-bottom-right-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.rounded-t-md{border-top-left-radius:var(--radius-md);border-top-right-radius:var(--radius-md)}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-y{border-top-width:1px;border-bottom-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-0{border-top-width:0px}.border-dashed{border-style:dashed}.border-\\[hsl\\(144_8\\%_91\\%\\)\\]{--tw-border-opacity: 1;border-color:hsl(144 8% 91% / var(--tw-border-opacity, 1))}.border-brand{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.border-brand-border{border-color:var(--brand-border)}.border-brand\\/30{border-color:hsl(var(--brand-hsl) / .3)}.border-brand\\/40{border-color:hsl(var(--brand-hsl) / .4)}.border-danger\\/20{border-color:hsl(var(--danger) / .2)}.border-danger\\/30{border-color:hsl(var(--danger) / .3)}.border-info\\/20{border-color:hsl(var(--info) / .2)}.border-info\\/30{border-color:hsl(var(--info) / .3)}.border-line{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.border-line-focus{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.border-line-strong{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.border-line-subtle\\/50{border-color:hsl(var(--border-subtle) / .5)}.border-line-subtle\\/90{border-color:hsl(var(--border-subtle) / .9)}.border-slate-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity, 1))}.border-slate-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity, 1))}.border-success{--tw-border-opacity: 1;border-color:hsl(var(--success) / var(--tw-border-opacity, 1))}.border-success\\/20{border-color:hsl(var(--success) / .2)}.border-success\\/30{border-color:hsl(var(--success) / .3)}.border-text-primary{--tw-border-opacity: 1;border-color:hsl(var(--text-primary) / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-warning\\/20{border-color:hsl(var(--warning) / .2)}.border-warning\\/30{border-color:hsl(var(--warning) / .3)}.border-white\\/70{border-color:#ffffffb3}.border-white\\/80{border-color:#fffc}.border-white\\/90{border-color:#ffffffe6}.border-l-brand{--tw-border-opacity: 1;border-left-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.bg-\\[var\\(--overlay-backdrop-strong\\)\\]{background-color:var(--overlay-backdrop-strong)}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\\/10{background-color:#0000001a}.bg-black\\/40{background-color:#0006}.bg-black\\/80{background-color:#000c}.bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.bg-brand-subtle{background-color:var(--brand-subtle)}.bg-brand\\/10{background-color:hsl(var(--brand-hsl) / .1)}.bg-brand\\/5{background-color:hsl(var(--brand-hsl) / .05)}.bg-danger{--tw-bg-opacity: 1;background-color:hsl(var(--danger) / var(--tw-bg-opacity, 1))}.bg-danger-subtle{background-color:hsl(var(--danger-subtle))}.bg-danger\\/10{background-color:hsl(var(--danger) / .1)}.bg-info-subtle{background-color:hsl(var(--info-subtle))}.bg-line{--tw-bg-opacity: 1;background-color:hsl(var(--border-default) / var(--tw-bg-opacity, 1))}.bg-line-subtle{--tw-bg-opacity: 1;background-color:hsl(var(--border-subtle) / var(--tw-bg-opacity, 1))}.bg-success{--tw-bg-opacity: 1;background-color:hsl(var(--success) / var(--tw-bg-opacity, 1))}.bg-success-subtle{background-color:hsl(var(--success-subtle))}.bg-success-surface{background-color:hsl(var(--success-surface))}.bg-surface-0{--tw-bg-opacity: 1;background-color:hsl(var(--surface-0) / var(--tw-bg-opacity, 1))}.bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.bg-surface-3{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.bg-surface-inset{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.bg-text-primary{--tw-bg-opacity: 1;background-color:hsl(var(--text-primary) / var(--tw-bg-opacity, 1))}.bg-text-tertiary{--tw-bg-opacity: 1;background-color:hsl(var(--text-tertiary) / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-warning{--tw-bg-opacity: 1;background-color:hsl(var(--warning) / var(--tw-bg-opacity, 1))}.bg-warning-subtle{background-color:hsl(var(--warning-subtle))}.bg-warning\\/10{background-color:hsl(var(--warning) / .1)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\\/10{background-color:#ffffff1a}.bg-white\\/25{background-color:#ffffff40}.fill-text-primary{fill:hsl(var(--text-primary) / 1)}.stroke-\\[3\\]{stroke-width:3}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.\\!p-0{padding:0!important}.p-0{padding:0}.p-0\\.5{padding:2px}.p-1{padding:4px}.p-1\\.5{padding:6px}.p-2{padding:8px}.p-3{padding:12px}.p-3\\.5{padding:14px}.p-4{padding:16px}.p-5{padding:20px}.p-6{padding:24px}.p-7{padding:28px}.p-8{padding:32px}.p-\\[18px\\]{padding:18px}.px-0{padding-left:0;padding-right:0}.px-1\\.5{padding-left:6px;padding-right:6px}.px-2{padding-left:8px;padding-right:8px}.px-2\\.5{padding-left:10px;padding-right:10px}.px-3{padding-left:12px;padding-right:12px}.px-4{padding-left:16px;padding-right:16px}.px-5{padding-left:20px;padding-right:20px}.px-6{padding-left:24px;padding-right:24px}.px-9{padding-left:36px;padding-right:36px}.py-0\\.5{padding-top:2px;padding-bottom:2px}.py-1{padding-top:4px;padding-bottom:4px}.py-1\\.5{padding-top:6px;padding-bottom:6px}.py-10{padding-top:40px;padding-bottom:40px}.py-16{padding-top:64px;padding-bottom:64px}.py-2{padding-top:8px;padding-bottom:8px}.py-2\\.5{padding-top:10px;padding-bottom:10px}.py-3{padding-top:12px;padding-bottom:12px}.py-3\\.5{padding-top:14px;padding-bottom:14px}.py-4{padding-top:16px;padding-bottom:16px}.py-5{padding-top:20px;padding-bottom:20px}.py-6{padding-top:24px;padding-bottom:24px}.py-8{padding-top:32px;padding-bottom:32px}.pb-1{padding-bottom:4px}.pb-3{padding-bottom:12px}.pb-4{padding-bottom:16px}.pl-3{padding-left:12px}.pl-4{padding-left:16px}.pl-5{padding-left:20px}.pl-8{padding-left:32px}.pr-10{padding-right:40px}.pr-3{padding-right:12px}.pr-4{padding-right:16px}.pt-0{padding-top:0}.pt-1{padding-top:4px}.pt-2\\.5{padding-top:10px}.pt-4{padding-top:16px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-display{font-family:var(--font-display),ui-sans-serif,system-ui,sans-serif}.font-mono{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace}.font-sans{font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif}.text-2xs{font-size:clamp(10.5px,10.19px + .082vw,11.5px);line-height:1.333}.text-\\[0\\.72rem\\]{font-size:11.52px}.text-\\[1\\.45rem\\]{font-size:23.2px}.text-\\[1\\.75rem\\]{font-size:28px}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.text-base{font-size:clamp(14px,13.39px + .163vw,16px);line-height:1.5}.text-lg{font-size:clamp(17px,16.39px + .163vw,19px);line-height:1.471}.text-sm{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.text-xl{font-size:clamp(20px,19.08px + .245vw,23px);line-height:1.45}.text-xs{font-size:clamp(12px,11.69px + .082vw,13px);line-height:1.333}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-4{line-height:16px}.leading-5{line-height:20px}.leading-8{line-height:32px}.leading-\\[1\\.55\\]{line-height:1.55}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.text-\\[hsl\\(145_5\\%_42\\%\\)\\]{--tw-text-opacity: 1;color:hsl(145 5% 42% / var(--tw-text-opacity, 1))}.text-brand{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.text-brand-fg{color:var(--brand-fg)}.text-brand\\/50{color:hsl(var(--brand-hsl) / .5)}.text-danger{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.text-danger\\/80{color:hsl(var(--danger) / .8)}.text-info{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-slate-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.text-success{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.text-text-disabled{--tw-text-opacity: 1;color:hsl(var(--text-disabled) / var(--tw-text-opacity, 1))}.text-text-inverse{--tw-text-opacity: 1;color:hsl(var(--text-inverse) / var(--tw-text-opacity, 1))}.text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.text-text-tertiary{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-warning{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\\/90{color:#ffffffe6}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.accent-brand{accent-color:hsl(var(--brand-hsl) / 1)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.\\!shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1) !important;--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\\[0_24px_70px_-28px_rgba\\(16\\,24\\,18\\,0\\.45\\)\\]{--tw-shadow: 0 24px 70px -28px rgba(16,24,18,.45);--tw-shadow-colored: 0 24px 70px -28px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: var(--shadow-lg);--tw-shadow-colored: var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: var(--shadow-md);--tw-shadow-colored: var(--shadow-md);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xs{--tw-shadow: var(--shadow-xs);--tw-shadow-colored: var(--shadow-xs);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.outline-2{outline-width:2px}.outline-offset-0{outline-offset:0px}.outline-transparent{outline-color:transparent}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-4{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-brand{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--brand-hsl) / var(--tw-ring-opacity, 1))}.ring-brand-subtle{--tw-ring-color: var(--brand-subtle)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-\\[2px\\]{--tw-backdrop-blur: blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,border-color\\,color\\,box-shadow\\]{transition-property:background-color,border-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\,opacity\\]{transition-property:background-color,color,border-color,box-shadow,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\]{transition-property:background-color,color,border-color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,box-shadow\\]{transition-property:background-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\]{transition-property:background-color,color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,box-shadow\\,background-color\\]{transition-property:border-color,box-shadow,background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,outline-color\\,box-shadow\\,background-color\\,transform\\]{transition-property:border-color,outline-color,box-shadow,background-color,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\,height\\,box-shadow\\,background-color\\,border-color\\,transform\\,opacity\\]{transition-property:max-width,height,box-shadow,background-color,border-color,transform,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\]{transition-property:max-width;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[opacity\\,transform\\]{transition-property:opacity,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-\\[var\\(--issue-marker-expand-duration\\)\\]{transition-duration:var(--issue-marker-expand-duration)}.duration-fast{transition-duration:var(--duration-fast)}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:var(--ease-in-out)}.ease-out{transition-timing-function:var(--ease-out)}@keyframes float-gentle{0%,to{transform:translateY(0)}50%{transform:translateY(-2px)}}@keyframes toast-slide{0%{opacity:0;transform:translateY(-14px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes gradient-shift{0%,to{background-position:0% 50%}50%{background-position:100% 50%}}.issue-overlay-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.issue-marker-breathe{animation:float-gentle 4.8s var(--ease-in-out) infinite}.issue-marker-breathe:hover,.issue-marker-breathe:focus-visible,.issue-marker-breathe:focus-within{animation-play-state:paused}.\\[overflow-wrap\\:anywhere\\]{overflow-wrap:anywhere}.marker\\:text-text-tertiary *::marker{color:hsl(var(--text-tertiary))}.marker\\:text-text-tertiary::marker{color:hsl(var(--text-tertiary))}.file\\:border-0::file-selector-button{border-width:0px}.file\\:bg-transparent::file-selector-button{background-color:transparent}.file\\:text-sm::file-selector-button{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.file\\:font-medium::file-selector-button{font-weight:500}.file\\:text-text-primary::file-selector-button{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::-moz-placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.first\\:mt-0:first-child{margin-top:0}.first\\:border-t-0:first-child{border-top-width:0px}.first\\:pt-0:first-child{padding-top:0}.focus-within\\:z-\\[10001\\]:focus-within{z-index:10001}.focus-within\\:border-line-focus:focus-within{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.hover\\:z-\\[10001\\]:hover{z-index:10001}.hover\\:border-line:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.hover\\:border-line-strong:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.hover\\:border-line-subtle:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.hover\\:bg-\\[hsl\\(144_8\\%_96\\%\\)\\]:hover{--tw-bg-opacity: 1;background-color:hsl(144 8% 96% / var(--tw-bg-opacity, 1))}.hover\\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.hover\\:bg-brand-hover:hover{background-color:var(--brand-hover)}.hover\\:bg-brand\\/40:hover{background-color:hsl(var(--brand-hsl) / .4)}.hover\\:bg-danger-subtle:hover{background-color:hsl(var(--danger-subtle))}.hover\\:bg-danger\\/10:hover{background-color:hsl(var(--danger) / .1)}.hover\\:bg-slate-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.hover\\:bg-slate-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2\\/60:hover{background-color:hsl(var(--surface-2) / .6)}.hover\\:bg-surface-3:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-inset:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.hover\\:bg-transparent:hover{background-color:transparent}.hover\\:bg-white\\/20:hover{background-color:#fff3}.hover\\:text-\\[hsl\\(150_10\\%_12\\%\\)\\]:hover{--tw-text-opacity: 1;color:hsl(150 10% 12% / var(--tw-text-opacity, 1))}.hover\\:text-brand-hover:hover{color:var(--brand-hover)}.hover\\:text-danger:hover{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.hover\\:text-slate-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.hover\\:text-text-primary:hover{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.hover\\:text-text-secondary:hover{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:opacity-90:hover{opacity:.9}.focus\\:border-brand:focus{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.focus\\:bg-surface-2:focus{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus\\:text-text-primary:focus{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus\\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:h-\\[var\\(--issue-sticker-hover-size\\)\\]:focus-visible{height:var(--issue-sticker-hover-size)}.focus-visible\\:max-w-\\[160px\\]:focus-visible{max-width:160px}.focus-visible\\:max-w-\\[480px\\]:focus-visible{max-width:480px}.focus-visible\\:border-line-focus:focus-visible{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.focus-visible\\:border-transparent:focus-visible{border-color:transparent}.focus-visible\\:bg-slate-50:focus-visible{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-1:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-2:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus-visible\\:text-text-primary:focus-visible{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus-visible\\:shadow-focus:focus-visible{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus-visible\\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:outline-line-focus:focus-visible{outline-color:hsl(var(--border-focus) / 1)}.focus-visible\\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-4:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-brand-subtle:focus-visible{--tw-ring-color: var(--brand-subtle)}.focus-visible\\:ring-white\\/40:focus-visible{--tw-ring-color: rgb(255 255 255 / .4)}.active\\:bg-brand-active:active{background-color:var(--brand-active)}.active\\:bg-brand\\/60:active{background-color:hsl(var(--brand-hsl) / .6)}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-40:disabled{opacity:.4}.disabled\\:opacity-50:disabled{opacity:.5}.group\\/marker:hover .group-hover\\/marker\\:h-\\[var\\(--issue-sticker-hover-size\\)\\]{height:var(--issue-sticker-hover-size)}.group\\/marker:hover .group-hover\\/marker\\:max-w-\\[160px\\]{max-width:160px}.group\\/marker:hover .group-hover\\/marker\\:max-w-\\[480px\\]{max-width:480px}.group\\/marker:hover .group-hover\\/marker\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\\/marker:hover .group-hover\\/marker\\:bg-brand-hover{background-color:var(--brand-hover)}.group\\/marker:hover .group-hover\\/marker\\:opacity-100{opacity:1}.group\\/marker:hover .group-hover\\/marker\\:shadow-xl{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.group:focus-visible .group-focus-visible\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:focus-visible .group-focus-visible\\:opacity-100{opacity:1}.group.toaster .group-\\[\\.toaster\\]\\:isolate{isolation:isolate}.group.toast .group-\\[\\.toast\\]\\:rounded-md,.group.toaster .group-\\[\\.toaster\\]\\:rounded-md{border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:border{border-width:1px}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-danger\\/30{border-color:hsl(var(--danger) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-info\\/30{border-color:hsl(var(--info) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-success\\/30{border-color:hsl(var(--success) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-warning\\/30{border-color:hsl(var(--warning) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-danger-subtle{background-color:hsl(var(--danger-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-info-subtle{background-color:hsl(var(--info-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-warning-subtle{background-color:hsl(var(--warning-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:px-4{padding-left:16px;padding-right:16px}.group.toaster .group-\\[\\.toaster\\]\\:py-3{padding-top:12px;padding-bottom:12px}.group.toast .group-\\[\\.toast\\]\\:text-sm{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.group.toast .group-\\[\\.toast\\]\\:text-xs{font-size:clamp(12px,11.69px + .082vw,13px);line-height:1.333}.group.toast .group-\\[\\.toast\\]\\:font-medium{font-weight:500}.group.toast .group-\\[\\.toast\\]\\:text-brand-fg{color:var(--brand-fg)}.group.toast .group-\\[\\.toast\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:absolute:before{content:var(--tw-content);position:absolute}.group.toaster .group-\\[\\.toaster\\]\\:before\\:inset-0:before{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.group.toaster .group-\\[\\.toaster\\]\\:before\\:-z-10:before{content:var(--tw-content);z-index:-10}.group.toaster .group-\\[\\.toaster\\]\\:before\\:rounded-md:before{content:var(--tw-content);border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:bg-surface-1:before{content:var(--tw-content);--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:before\\:content-\\[\\'\\'\\]:before{--tw-content: "";content:var(--tw-content)}.peer:focus-visible~.peer-focus-visible\\:shadow-focus{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.peer:disabled~.peer-disabled\\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\\:opacity-60{opacity:.6}.aria-disabled\\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\\:opacity-40[aria-disabled=true]{opacity:.4}.data-\\[disabled\\]\\:pointer-events-none[data-disabled]{pointer-events:none}@keyframes dialog-out{0%{opacity:1;transform:translate(-50%,-50%) scale(1)}to{opacity:0;transform:translate(-50%,calc(-50% + 8px)) scale(.985)}}.data-\\[state\\=closed\\]\\:animate-dialog-out[data-state=closed]{animation:dialog-out var(--duration-out) var(--ease-out) forwards}@keyframes fade-out{0%{opacity:1}to{opacity:0}}.data-\\[state\\=closed\\]\\:animate-fade-out[data-state=closed]{animation:fade-out var(--duration-out) var(--ease-out) forwards}@keyframes scale-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.97)}}.data-\\[state\\=closed\\]\\:animate-scale-out[data-state=closed]{animation:scale-out var(--duration-out) var(--ease-out) forwards}@keyframes sheet-out-left{0%{transform:translate(0)}to{transform:translate(-100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-left[data-state=closed]{animation:sheet-out-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-out-right{0%{transform:translate(0);opacity:1}to{transform:translate(100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-right[data-state=closed]{animation:sheet-out-right var(--duration-base) var(--ease-out) forwards}.data-\\[state\\=delayed-open\\]\\:animate-scale-in[data-state=delayed-open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes dialog-in{0%{opacity:0;transform:translate(-50%,calc(-50% + 12px)) scale(.985)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}.data-\\[state\\=open\\]\\:animate-dialog-in[data-state=open]{animation:dialog-in var(--duration-base) var(--ease-out) forwards}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.data-\\[state\\=open\\]\\:animate-fade-in[data-state=open]{animation:fade-in var(--duration-base) var(--ease-out) forwards}@keyframes scale-in{0%{opacity:0;transform:scale(.98)}to{opacity:1;transform:scale(1)}}.data-\\[state\\=open\\]\\:animate-scale-in[data-state=open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-left{0%{transform:translate(-100%);opacity:.6}to{transform:translate(0);opacity:1}}.data-\\[state\\=open\\]\\:animate-sheet-in-left[data-state=open]{animation:sheet-in-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-right{0%{transform:translate(100%);opacity:.6}to{transform:translate(0)}}.data-\\[state\\=open\\]\\:animate-sheet-in-right[data-state=open]{animation:sheet-in-right var(--duration-base) var(--ease-out) forwards}.data-\\[range-end\\=true\\]\\:rounded-md[data-range-end=true]{border-radius:var(--radius-md)}.data-\\[range-middle\\=true\\]\\:rounded-none[data-range-middle=true]{border-radius:0}.data-\\[range-start\\=true\\]\\:rounded-md[data-range-start=true]{border-radius:var(--radius-md)}.data-\\[state\\=open\\]\\:border-line-focus[data-state=open]{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.data-\\[highlighted\\]\\:bg-surface-2[data-highlighted]{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.data-\\[range-end\\=true\\]\\:bg-brand[data-range-end=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[range-middle\\=true\\]\\:bg-transparent[data-range-middle=true]{background-color:transparent}.data-\\[range-start\\=true\\]\\:bg-brand[data-range-start=true],.data-\\[selected-single\\=true\\]\\:bg-brand[data-selected-single=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[state\\=selected\\]\\:bg-brand-subtle[data-state=selected]{background-color:var(--brand-subtle)}.data-\\[today\\=true\\]\\:font-semibold[data-today=true]{font-weight:600}.data-\\[highlighted\\]\\:text-text-primary[data-highlighted]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[placeholder\\]\\:text-text-tertiary[data-placeholder]{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.data-\\[range-end\\=true\\]\\:text-brand-fg[data-range-end=true]{color:var(--brand-fg)}.data-\\[range-middle\\=true\\]\\:text-text-primary[data-range-middle=true]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[range-start\\=true\\]\\:text-brand-fg[data-range-start=true],.data-\\[selected-single\\=true\\]\\:text-brand-fg[data-selected-single=true]{color:var(--brand-fg)}.data-\\[state\\=active\\]\\:text-text-primary[data-state=active],.data-\\[state\\=checked\\]\\:text-text-primary[data-state=checked]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[today\\=true\\]\\:text-brand[data-today=true]{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.data-\\[disabled\\]\\:opacity-50[data-disabled]{opacity:.5}.data-\\[state\\=open\\]\\:shadow-focus[data-state=open]{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\\[range-end\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:bg-brand-hover:hover[data-selected-single=true]{background-color:var(--brand-hover)}.data-\\[range-end\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:text-brand-fg:hover[data-selected-single=true]{color:var(--brand-fg)}@media(prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}}@media(min-width:640px){.sm\\:flex-row{flex-direction:row}.sm\\:items-start{align-items:flex-start}.sm\\:items-center{align-items:center}.sm\\:justify-end{justify-content:flex-end}.sm\\:justify-between{justify-content:space-between}.sm\\:gap-2\\.5{gap:10px}.sm\\:p-5{padding:20px}.sm\\:p-6{padding:24px}.sm\\:text-2xl{font-size:clamp(26px,24.78px + .327vw,30px);line-height:1.308}.sm\\:text-\\[2\\.1rem\\]{font-size:33.6px}}@media(min-width:768px){.md\\:flex{display:flex}.md\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\\:grid-cols-\\[minmax\\(0\\,1fr\\)_minmax\\(260px\\,340px\\)\\]{grid-template-columns:minmax(0,1fr) minmax(260px,340px)}}.\\[\\&\\>\\*\\:not\\(summary\\)\\]\\:pl-4>*:not(summary){padding-left:16px}.\\[\\&\\>span\\]\\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\\[\\&\\>tr\\]\\:last\\:border-b-0:last-child>tr{border-bottom-width:0px}.\\[\\&\\[data-state\\=open\\]\\>span\\[data-chevron\\]\\]\\:rotate-180[data-state=open]>span[data-chevron]{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-danger [data-icon]{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-info [data-icon]{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-success [data-icon]{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-warning [data-icon]{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.\\[\\&_tr\\]\\:border-b tr{border-bottom-width:1px}.\\[\\&_tr\\]\\:border-line-subtle tr{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}`;
|
|
40249
|
+
const globalsCSS = `:root,:host{color-scheme:light;--brand-h: 150;--brand-s: 100%;--brand-l: 34%;--brand-hsl: var(--brand-h) var(--brand-s) var(--brand-l);--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) calc(var(--brand-s) + 3%) calc(var(--brand-l) - 4%));--brand-active: hsl(var(--brand-h) calc(var(--brand-s) + 2%) calc(var(--brand-l) - 8%));--brand-subtle: hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14);--brand-border: hsl(var(--brand-h) calc(var(--brand-s) + 8%) calc(var(--brand-l) + 8%) / .34);--brand-fg: hsl(0 0% 100%);--brand-ring: hsl(var(--brand-h) calc(var(--brand-s) + 12%) calc(var(--brand-l) + 10%) / .22);--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-display: var(--font-sans);--font-mono: var(--font-sans);--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--text-disabled: 145 4% 70%;--text-inverse: 0 0% 100%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--border-focus: var(--brand-h) var(--brand-s) var(--brand-l);--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 52%;--warning-subtle: 34 82% 52% / .14;--danger: 3 68% 56%;--danger-subtle: 3 68% 56% / .12;--danger-deep: 3 62% 40%;--info: 202 52% 44%;--info-subtle: 202 52% 44% / .12;--accent-terra: 13 52% 47%;--accent-terra-subtle: 13 52% 47% / .1;--accent-terra-deep: 13 48% 44%;--accent-blue: 213 86% 56%;--accent-blue-subtle: 213 92% 56% / .12;--accent-blue-deep: 216 78% 40%;--accent-blue-border: 213 86% 62% / .36;--accent-cream: 38 52% 88%;--accent-cream-warm: 40 56% 95%;--accent-cream-deep: 38 48% 82%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 11%;--radius-xs: 4px;--radius-sm: 8px;--radius-md: 12px;--radius-lg: 16px;--radius-xl: 20px;--radius-2xl: 24px;--radius-pill: 9999px;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 3px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 14%) / .24), 0 6px 20px hsl(var(--brand-h) calc(var(--brand-s) - 70%) calc(var(--brand-l) - 19%) / .16);--duration-instant: 90ms;--duration-fast: .16s;--duration-base: .26s;--duration-out: .18s;--duration-slow: .36s;--ease-out: cubic-bezier(.23, 1, .32, 1);--ease-in-out: cubic-bezier(.45, 0, .15, 1);--ease-spring: cubic-bezier(.18, .94, .32, 1.08);--grid-line: 0 0% 92%}.dark,:host(.dark){color-scheme:dark;--brand-l: 34%;--brand-fg: hsl(0 0% 100%);--surface-0: 150 8% 7%;--surface-1: 150 6% 10%;--surface-2: 150 5% 14%;--surface-3: 150 4% 18%;--surface-inset: 150 6% 6%;--overlay-backdrop: hsl(0 0% 0% / .56);--overlay-backdrop-strong: hsl(0 0% 0% / .8);--text-primary: 40 16% 93%;--text-secondary: 36 8% 68%;--text-tertiary: 34 6% 50%;--text-disabled: 30 5% 34%;--text-inverse: 150 8% 10%;--border-subtle: 150 6% 16%;--border-default: 150 5% 22%;--border-strong: 150 4% 34%;--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 62%;--danger: 2 70% 64%;--danger-deep: 2 80% 76%;--info: 202 54% 62%;--accent-terra: 13 56% 62%;--accent-terra-subtle: 13 56% 62% / .14;--accent-terra-deep: 13 52% 56%;--accent-blue: 210 92% 68%;--accent-blue-subtle: 210 92% 68% / .18;--accent-blue-deep: 209 100% 78%;--accent-blue-border: 210 92% 72% / .44;--accent-cream: 38 30% 26%;--accent-cream-warm: 38 22% 18%;--accent-cream-deep: 38 26% 32%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 8%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .2);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .3), 0 1px 2px -1px hsl(0 0% 0% / .24);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .34), 0 2px 4px -2px hsl(0 0% 0% / .2);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .38), 0 4px 6px -4px hsl(0 0% 0% / .24);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .44), 0 8px 10px -6px hsl(0 0% 0% / .28);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .16);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 24%) / .44), 0 6px 20px hsl(0 0% 0% / .32);--grid-line: 150 6% 14%}*{border-color:hsl(var(--border-default))}html{font-family:var(--font-sans),ui-sans-serif,system-ui,-apple-system,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-feature-settings:"cv11","ss01","ss03";background-color:hsl(var(--surface-0))}body{margin:0;min-height:100vh;color:hsl(var(--text-primary));background-color:hsl(var(--surface-0))}::-moz-selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}::selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:"ss01","ss02","cv11"}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:hsl(var(--border-strong) / .52);border-radius:var(--radius-pill);border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:hsl(var(--border-strong) / .9);background-clip:padding-box;border:2px solid transparent}.app-canvas,.grid-canvas{background-color:hsl(var(--surface-0))}.onboarding-canvas{word-break:keep-all;overflow-wrap:break-word;--surface-0: var(--brand-h) var(--brand-s) var(--brand-l);--surface-1: 0 0% 100%;--surface-2: var(--brand-h) 62% 28%;--surface-3: var(--brand-h) 60% 25%;--surface-inset: var(--brand-h) 62% 28%;--text-primary: 0 0% 100%;--text-secondary: var(--brand-h) 46% 90%;--text-tertiary: var(--brand-h) 34% 84%;--text-disabled: var(--brand-h) 20% 72%;--border-subtle: var(--brand-h) 44% 52%;--border-default: var(--brand-h) 40% 58%;--border-strong: var(--brand-h) 36% 70%;--border-focus: 0 0% 100%;--brand-hsl: 0 0% 100%;--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) 24% 94%);--brand-active: hsl(var(--brand-h) 20% 88%);--brand-fg: hsl(var(--brand-h) var(--brand-s) 24%);--brand-ring: hsl(0 0% 100% / .4);--danger: 6 96% 86%;--danger-subtle: 6 96% 86% / .18;--danger-deep: 6 96% 92%;--warning: 42 96% 82%;--warning-subtle: 42 96% 82% / .18}.onboarding-canvas .bg-surface-1,.onboarding-canvas input,.onboarding-canvas textarea,.onboarding-canvas [role=combobox]{--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--surface-2: 144 8% 96%;--surface-inset: 144 6% 95%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--brand-hsl: var(--brand-h) var(--brand-s) var(--brand-l);--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) calc(var(--brand-s) + 3%) calc(var(--brand-l) - 4%));--brand-active: hsl(var(--brand-h) calc(var(--brand-s) + 2%) calc(var(--brand-l) - 8%));--brand-fg: hsl(0 0% 100%);--brand-ring: hsl(var(--brand-h) calc(var(--brand-s) + 12%) calc(var(--brand-l) + 10%) / .22);--warning: 34 82% 52%;--warning-subtle: 34 82% 52% / .14;--danger: 3 68% 56%;--danger-subtle: 3 68% 56% / .12;--danger-deep: 3 62% 40%}@keyframes onboarding-step-in{0%{opacity:0;transform:translate(96px)}to{opacity:1;transform:translate(0)}}.onboarding-step-in{animation:onboarding-step-in var(--duration-slow) var(--ease-out) forwards}@keyframes onboarding-enter-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.onboarding-enter{position:fixed;top:0;right:0;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;animation:onboarding-enter-up var(--duration-base) var(--ease-out) forwards}body:has(.onboarding-canvas){background-color:hsl(var(--brand-h) var(--brand-s) var(--brand-l))}.panel-shell,.surface-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-sm)}.panel-shell-muted,.surface-shell-muted{background:hsl(var(--surface-2));box-shadow:var(--shadow-xs)}.panel-shell-subtle{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.panel-shell-elevated{border:1px solid hsl(var(--border-default));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.utility-chip,.floating-chip{display:inline-flex;align-items:center;gap:8px;border:1px solid hsl(var(--border-default));border-radius:var(--radius-pill);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.hairline{border-bottom:1px solid hsl(var(--border-subtle))}.mono-label{font-family:var(--font-mono),ui-monospace,monospace;font-size:11px;text-transform:uppercase;color:hsl(var(--text-tertiary))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root,:host{--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-mono: var(--font-sans);--issue-marker-expand-duration: .52s;--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 52%;--text-disabled: 145 4% 70%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--grid-line: 0 0% 92%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 4px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04)}*{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}#issue-sticker-shadow-root{all:initial;display:block;background-color:transparent;--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1));font-family:var(--font-sans);line-height:1.5}.\\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\\!visible{visibility:visible!important}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-x-1{left:4px;right:4px}.inset-y-0{top:0;bottom:0}.-bottom-px{bottom:-1px}.bottom-0{bottom:0}.bottom-4{bottom:16px}.bottom-6{bottom:24px}.left-0{left:0}.left-1\\/2{left:50%}.left-2{left:8px}.left-4{left:16px}.left-\\[50\\%\\]{left:50%}.right-0{right:0}.right-2{right:8px}.right-3{right:12px}.right-4{right:16px}.right-5{right:20px}.right-6{right:24px}.top-0{top:0}.top-1{top:4px}.top-1\\/2{top:50%}.top-2{top:8px}.top-3{top:12px}.top-4{top:16px}.top-5{top:20px}.top-\\[50\\%\\]{top:50%}.top-\\[calc\\(\\(3\\.5rem-1\\.75rem\\)\\/2\\)\\]{top:14px}.top-full{top:100%}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-\\[1000000\\]{z-index:1000000}.z-\\[1000003\\]{z-index:1000003}.z-\\[1000004\\]{z-index:1000004}.z-\\[1000005\\]{z-index:1000005}.z-\\[1000006\\]{z-index:1000006}.z-\\[1000007\\]{z-index:1000007}.z-\\[1000008\\]{z-index:1000008}.z-\\[1000010\\]{z-index:1000010}.z-\\[1000011\\]{z-index:1000011}.z-\\[10001\\]{z-index:10001}.z-\\[999999\\]{z-index:999999}.z-\\[9999\\]{z-index:9999}.m-0{margin:0}.-mx-2{margin-left:-8px;margin-right:-8px}.mx-3{margin-left:12px;margin-right:12px}.my-1{margin-top:4px;margin-bottom:4px}.my-2{margin-top:8px;margin-bottom:8px}.my-2\\.5{margin-top:10px;margin-bottom:10px}.my-3{margin-top:12px;margin-bottom:12px}.my-4{margin-top:16px;margin-bottom:16px}.mb-0\\.5{margin-bottom:2px}.mb-1{margin-bottom:4px}.mb-2{margin-bottom:8px}.mb-3{margin-bottom:12px}.mb-5{margin-bottom:20px}.ml-0\\.5{margin-left:2px}.ml-4{margin-left:16px}.mr-1\\.5{margin-right:6px}.mr-2{margin-right:8px}.mt-0{margin-top:0}.mt-0\\.5{margin-top:2px}.mt-1{margin-top:4px}.mt-2{margin-top:8px}.mt-3{margin-top:12px}.mt-4{margin-top:16px}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.\\!h-auto{height:auto!important}.h-1\\.5{height:6px}.h-10{height:40px}.h-11{height:44px}.h-2{height:8px}.h-24{height:96px}.h-3{height:12px}.h-3\\.5{height:14px}.h-4{height:16px}.h-5{height:20px}.h-6{height:24px}.h-7{height:28px}.h-8{height:32px}.h-9{height:36px}.h-\\[1\\.4rem\\]{height:22.4px}.h-\\[100vh\\]{height:100vh}.h-\\[18px\\]{height:18px}.h-\\[220px\\]{height:220px}.h-\\[22px\\]{height:22px}.h-\\[30px\\]{height:30px}.h-\\[min\\(36vh\\,320px\\)\\]{height:min(36vh,320px)}.h-\\[min\\(480px\\,calc\\(100vh-64px\\)\\)\\]{height:min(480px,calc(100vh - 64px))}.h-\\[min\\(54vh\\,520px\\)\\]{height:min(54vh,520px)}.h-\\[min\\(560px\\,calc\\(100vh-32px\\)\\)\\]{height:min(560px,calc(100vh - 32px))}.h-\\[var\\(--issue-sticker-size\\)\\]{height:var(--issue-sticker-size)}.h-\\[var\\(--radix-select-trigger-height\\)\\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.max-h-24{max-height:96px}.max-h-40{max-height:160px}.max-h-56{max-height:224px}.max-h-80{max-height:320px}.max-h-96{max-height:384px}.max-h-\\[150px\\]{max-height:150px}.max-h-\\[220px\\]{max-height:220px}.max-h-\\[320px\\]{max-height:320px}.max-h-\\[420px\\]{max-height:420px}.max-h-\\[90vh\\]{max-height:90vh}.max-h-\\[calc\\(100vh-3rem\\)\\]{max-height:calc(100vh - 48px)}.max-h-\\[min\\(80vh\\,640px\\)\\]{max-height:min(80vh,640px)}.min-h-0{min-height:0px}.min-h-11{min-height:44px}.min-h-\\[108px\\]{min-height:108px}.min-h-\\[120px\\]{min-height:120px}.min-h-\\[140px\\]{min-height:140px}.min-h-\\[220px\\]{min-height:220px}.w-0\\.5{width:2px}.w-1{width:4px}.w-1\\.5{width:6px}.w-1\\/2{width:50%}.w-10{width:40px}.w-12{width:48px}.w-14{width:56px}.w-16{width:64px}.w-2{width:8px}.w-3{width:12px}.w-3\\.5{width:14px}.w-4{width:16px}.w-5{width:20px}.w-6{width:24px}.w-7{width:28px}.w-72{width:288px}.w-8{width:32px}.w-80{width:320px}.w-9{width:36px}.w-\\[1\\.4rem\\]{width:22.4px}.w-\\[18px\\]{width:18px}.w-\\[22\\.5rem\\]{width:360px}.w-\\[22rem\\]{width:352px}.w-\\[30px\\]{width:30px}.w-\\[38px\\]{width:38px}.w-\\[calc\\(100vw-32px\\)\\]{width:calc(100vw - 32px)}.w-\\[min\\(24rem\\,calc\\(100vw_-_1\\.5rem\\)\\)\\]{width:min(384px,calc(100vw - 24px))}.w-\\[min\\(30rem\\,calc\\(100vw_-_1\\.5rem\\)\\)\\]{width:min(480px,calc(100vw - 24px))}.w-\\[min\\(560px\\,calc\\(100vw-32px\\)\\)\\]{width:min(560px,calc(100vw - 32px))}.w-\\[var\\(--radix-popover-trigger-width\\)\\]{width:var(--radix-popover-trigger-width)}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-0{min-width:0px}.min-w-9{min-width:36px}.min-w-\\[12rem\\]{min-width:192px}.min-w-\\[200px\\]{min-width:200px}.min-w-\\[var\\(--radix-popover-trigger-width\\)\\]{min-width:var(--radix-popover-trigger-width)}.min-w-\\[var\\(--radix-select-trigger-width\\)\\]{min-width:var(--radix-select-trigger-width)}.max-w-\\[10rem\\]{max-width:160px}.max-w-\\[120px\\]{max-width:120px}.max-w-\\[160px\\]{max-width:160px}.max-w-\\[16rem\\]{max-width:256px}.max-w-\\[260px\\]{max-width:260px}.max-w-\\[280px\\]{max-width:280px}.max-w-\\[28rem\\]{max-width:448px}.max-w-\\[300px\\]{max-width:300px}.max-w-\\[360px\\]{max-width:360px}.max-w-\\[36rem\\]{max-width:576px}.max-w-\\[400px\\]{max-width:400px}.max-w-\\[420px\\]{max-width:420px}.max-w-\\[428px\\]{max-width:428px}.max-w-\\[480px\\]{max-width:480px}.max-w-\\[62ch\\]{max-width:62ch}.max-w-\\[640px\\]{max-width:640px}.max-w-\\[70ch\\]{max-width:70ch}.max-w-\\[90vw\\]{max-width:90vw}.max-w-\\[960px\\]{max-width:960px}.max-w-\\[calc\\(100vw-24px\\)\\]{max-width:calc(100vw - 24px)}.max-w-\\[var\\(--issue-sticker-size\\)\\]{max-width:var(--issue-sticker-size)}.max-w-full{max-width:100%}.max-w-md{max-width:448px}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.-translate-x-1{--tw-translate-x: -4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1{--tw-translate-x: 4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[-50\\%\\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[18px\\]{--tw-translate-x: 18px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[2px\\]{--tw-translate-x: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\\[-50\\%\\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes pulse-ring{0%,to{box-shadow:0 0 0 0 var(--brand-ring)}50%{box-shadow:0 0 0 8px transparent}}.animate-pulse-ring{animation:pulse-ring 1.8s var(--ease-in-out) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\\.5{gap:2px}.gap-1{gap:4px}.gap-1\\.5{gap:6px}.gap-2{gap:8px}.gap-2\\.5{gap:10px}.gap-3{gap:12px}.gap-3\\.5{gap:14px}.gap-4{gap:16px}.gap-5{gap:20px}.gap-6{gap:24px}.gap-x-5{-moz-column-gap:20px;column-gap:20px}.gap-y-2{row-gap:8px}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(4px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(4px * var(--tw-space-y-reverse))}.space-y-1\\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(6px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(6px * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(8px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(8px * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(12px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(12px * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(16px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(16px * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(20px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(20px * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(24px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(24px * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-line-subtle>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.break-keep{word-break:keep-all}.\\!rounded-none{border-radius:0!important}.rounded{border-radius:4px}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[18px\\]{border-radius:18px}.rounded-\\[20px\\]{border-radius:20px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-xs{border-radius:var(--radius-xs)}.rounded-b-md{border-bottom-right-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.rounded-t-md{border-top-left-radius:var(--radius-md);border-top-right-radius:var(--radius-md)}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-y{border-top-width:1px;border-bottom-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-0{border-top-width:0px}.border-dashed{border-style:dashed}.border-\\[hsl\\(144_8\\%_91\\%\\)\\]{--tw-border-opacity: 1;border-color:hsl(144 8% 91% / var(--tw-border-opacity, 1))}.border-brand{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.border-brand-border{border-color:var(--brand-border)}.border-brand\\/30{border-color:hsl(var(--brand-hsl) / .3)}.border-brand\\/40{border-color:hsl(var(--brand-hsl) / .4)}.border-danger\\/20{border-color:hsl(var(--danger) / .2)}.border-danger\\/30{border-color:hsl(var(--danger) / .3)}.border-info\\/20{border-color:hsl(var(--info) / .2)}.border-info\\/30{border-color:hsl(var(--info) / .3)}.border-line{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.border-line-focus{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.border-line-strong{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.border-line-subtle\\/50{border-color:hsl(var(--border-subtle) / .5)}.border-line-subtle\\/90{border-color:hsl(var(--border-subtle) / .9)}.border-slate-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity, 1))}.border-slate-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity, 1))}.border-success{--tw-border-opacity: 1;border-color:hsl(var(--success) / var(--tw-border-opacity, 1))}.border-success\\/20{border-color:hsl(var(--success) / .2)}.border-success\\/30{border-color:hsl(var(--success) / .3)}.border-text-primary{--tw-border-opacity: 1;border-color:hsl(var(--text-primary) / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-warning\\/20{border-color:hsl(var(--warning) / .2)}.border-warning\\/30{border-color:hsl(var(--warning) / .3)}.border-white\\/70{border-color:#ffffffb3}.border-white\\/80{border-color:#fffc}.border-white\\/90{border-color:#ffffffe6}.border-l-brand{--tw-border-opacity: 1;border-left-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.bg-\\[var\\(--overlay-backdrop-strong\\)\\]{background-color:var(--overlay-backdrop-strong)}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\\/10{background-color:#0000001a}.bg-black\\/40{background-color:#0006}.bg-black\\/80{background-color:#000c}.bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.bg-brand-subtle{background-color:var(--brand-subtle)}.bg-brand\\/10{background-color:hsl(var(--brand-hsl) / .1)}.bg-brand\\/5{background-color:hsl(var(--brand-hsl) / .05)}.bg-danger{--tw-bg-opacity: 1;background-color:hsl(var(--danger) / var(--tw-bg-opacity, 1))}.bg-danger-subtle{background-color:hsl(var(--danger-subtle))}.bg-danger\\/10{background-color:hsl(var(--danger) / .1)}.bg-info-subtle{background-color:hsl(var(--info-subtle))}.bg-line{--tw-bg-opacity: 1;background-color:hsl(var(--border-default) / var(--tw-bg-opacity, 1))}.bg-line-subtle{--tw-bg-opacity: 1;background-color:hsl(var(--border-subtle) / var(--tw-bg-opacity, 1))}.bg-success{--tw-bg-opacity: 1;background-color:hsl(var(--success) / var(--tw-bg-opacity, 1))}.bg-success-subtle{background-color:hsl(var(--success-subtle))}.bg-success-surface{background-color:hsl(var(--success-surface))}.bg-surface-0{--tw-bg-opacity: 1;background-color:hsl(var(--surface-0) / var(--tw-bg-opacity, 1))}.bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.bg-surface-3{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.bg-surface-inset{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.bg-text-primary{--tw-bg-opacity: 1;background-color:hsl(var(--text-primary) / var(--tw-bg-opacity, 1))}.bg-text-tertiary{--tw-bg-opacity: 1;background-color:hsl(var(--text-tertiary) / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-warning{--tw-bg-opacity: 1;background-color:hsl(var(--warning) / var(--tw-bg-opacity, 1))}.bg-warning-subtle{background-color:hsl(var(--warning-subtle))}.bg-warning\\/10{background-color:hsl(var(--warning) / .1)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\\/10{background-color:#ffffff1a}.bg-white\\/25{background-color:#ffffff40}.fill-text-primary{fill:hsl(var(--text-primary) / 1)}.stroke-\\[3\\]{stroke-width:3}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.\\!p-0{padding:0!important}.p-0{padding:0}.p-0\\.5{padding:2px}.p-1{padding:4px}.p-1\\.5{padding:6px}.p-2{padding:8px}.p-3{padding:12px}.p-3\\.5{padding:14px}.p-4{padding:16px}.p-5{padding:20px}.p-6{padding:24px}.p-7{padding:28px}.p-8{padding:32px}.p-\\[18px\\]{padding:18px}.px-0{padding-left:0;padding-right:0}.px-1\\.5{padding-left:6px;padding-right:6px}.px-2{padding-left:8px;padding-right:8px}.px-2\\.5{padding-left:10px;padding-right:10px}.px-3{padding-left:12px;padding-right:12px}.px-4{padding-left:16px;padding-right:16px}.px-5{padding-left:20px;padding-right:20px}.px-6{padding-left:24px;padding-right:24px}.px-9{padding-left:36px;padding-right:36px}.py-0\\.5{padding-top:2px;padding-bottom:2px}.py-1{padding-top:4px;padding-bottom:4px}.py-1\\.5{padding-top:6px;padding-bottom:6px}.py-10{padding-top:40px;padding-bottom:40px}.py-16{padding-top:64px;padding-bottom:64px}.py-2{padding-top:8px;padding-bottom:8px}.py-2\\.5{padding-top:10px;padding-bottom:10px}.py-3{padding-top:12px;padding-bottom:12px}.py-3\\.5{padding-top:14px;padding-bottom:14px}.py-4{padding-top:16px;padding-bottom:16px}.py-5{padding-top:20px;padding-bottom:20px}.py-6{padding-top:24px;padding-bottom:24px}.py-8{padding-top:32px;padding-bottom:32px}.pb-1{padding-bottom:4px}.pb-3{padding-bottom:12px}.pb-4{padding-bottom:16px}.pl-0{padding-left:0}.pl-3{padding-left:12px}.pl-4{padding-left:16px}.pl-5{padding-left:20px}.pl-8{padding-left:32px}.pr-10{padding-right:40px}.pr-3{padding-right:12px}.pr-4{padding-right:16px}.pt-0{padding-top:0}.pt-1{padding-top:4px}.pt-2\\.5{padding-top:10px}.pt-4{padding-top:16px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-display{font-family:var(--font-display),ui-sans-serif,system-ui,sans-serif}.font-mono{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace}.font-sans{font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif}.text-2xs{font-size:clamp(10.5px,10.19px + .082vw,11.5px);line-height:1.333}.text-\\[0\\.72rem\\]{font-size:11.52px}.text-\\[1\\.45rem\\]{font-size:23.2px}.text-\\[1\\.75rem\\]{font-size:28px}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.text-base{font-size:clamp(14px,13.39px + .163vw,16px);line-height:1.5}.text-lg{font-size:clamp(17px,16.39px + .163vw,19px);line-height:1.471}.text-sm{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.text-xl{font-size:clamp(20px,19.08px + .245vw,23px);line-height:1.45}.text-xs{font-size:clamp(12px,11.69px + .082vw,13px);line-height:1.333}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-4{line-height:16px}.leading-5{line-height:20px}.leading-8{line-height:32px}.leading-\\[1\\.55\\]{line-height:1.55}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.text-\\[hsl\\(145_5\\%_42\\%\\)\\]{--tw-text-opacity: 1;color:hsl(145 5% 42% / var(--tw-text-opacity, 1))}.text-brand{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.text-brand-fg{color:var(--brand-fg)}.text-brand\\/50{color:hsl(var(--brand-hsl) / .5)}.text-danger{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.text-danger\\/80{color:hsl(var(--danger) / .8)}.text-info{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-slate-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.text-success{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.text-text-disabled{--tw-text-opacity: 1;color:hsl(var(--text-disabled) / var(--tw-text-opacity, 1))}.text-text-inverse{--tw-text-opacity: 1;color:hsl(var(--text-inverse) / var(--tw-text-opacity, 1))}.text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.text-text-tertiary{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-warning{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\\/90{color:#ffffffe6}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.accent-brand{accent-color:hsl(var(--brand-hsl) / 1)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.\\!shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1) !important;--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\\[0_24px_70px_-28px_rgba\\(16\\,24\\,18\\,0\\.45\\)\\]{--tw-shadow: 0 24px 70px -28px rgba(16,24,18,.45);--tw-shadow-colored: 0 24px 70px -28px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: var(--shadow-lg);--tw-shadow-colored: var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: var(--shadow-md);--tw-shadow-colored: var(--shadow-md);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xs{--tw-shadow: var(--shadow-xs);--tw-shadow-colored: var(--shadow-xs);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.outline-2{outline-width:2px}.outline-offset-0{outline-offset:0px}.outline-transparent{outline-color:transparent}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-4{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-brand{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--brand-hsl) / var(--tw-ring-opacity, 1))}.ring-brand-subtle{--tw-ring-color: var(--brand-subtle)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-\\[2px\\]{--tw-backdrop-blur: blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,border-color\\,color\\,box-shadow\\]{transition-property:background-color,border-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\,opacity\\]{transition-property:background-color,color,border-color,box-shadow,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\]{transition-property:background-color,color,border-color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,box-shadow\\]{transition-property:background-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\]{transition-property:background-color,color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,box-shadow\\,background-color\\]{transition-property:border-color,box-shadow,background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,outline-color\\,box-shadow\\,background-color\\,transform\\]{transition-property:border-color,outline-color,box-shadow,background-color,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\,height\\,box-shadow\\,background-color\\,border-color\\,transform\\,opacity\\]{transition-property:max-width,height,box-shadow,background-color,border-color,transform,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\]{transition-property:max-width;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[opacity\\,transform\\]{transition-property:opacity,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-\\[var\\(--issue-marker-expand-duration\\)\\]{transition-duration:var(--issue-marker-expand-duration)}.duration-fast{transition-duration:var(--duration-fast)}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:var(--ease-in-out)}.ease-out{transition-timing-function:var(--ease-out)}@keyframes float-gentle{0%,to{transform:translateY(0)}50%{transform:translateY(-2px)}}@keyframes toast-slide{0%{opacity:0;transform:translateY(-14px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes gradient-shift{0%,to{background-position:0% 50%}50%{background-position:100% 50%}}.issue-overlay-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.issue-marker-breathe{animation:float-gentle 4.8s var(--ease-in-out) infinite}.issue-marker-breathe:hover,.issue-marker-breathe:focus-visible,.issue-marker-breathe:focus-within{animation-play-state:paused}.\\[overflow-wrap\\:anywhere\\]{overflow-wrap:anywhere}.marker\\:text-text-tertiary *::marker{color:hsl(var(--text-tertiary))}.marker\\:text-text-tertiary::marker{color:hsl(var(--text-tertiary))}.file\\:border-0::file-selector-button{border-width:0px}.file\\:bg-transparent::file-selector-button{background-color:transparent}.file\\:text-sm::file-selector-button{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.file\\:font-medium::file-selector-button{font-weight:500}.file\\:text-text-primary::file-selector-button{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::-moz-placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.first\\:mt-0:first-child{margin-top:0}.first\\:border-t-0:first-child{border-top-width:0px}.first\\:pt-0:first-child{padding-top:0}.focus-within\\:z-\\[10001\\]:focus-within{z-index:10001}.focus-within\\:border-line-focus:focus-within{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.hover\\:z-\\[10001\\]:hover{z-index:10001}.hover\\:border-line:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.hover\\:border-line-strong:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.hover\\:border-line-subtle:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.hover\\:bg-\\[hsl\\(144_8\\%_96\\%\\)\\]:hover{--tw-bg-opacity: 1;background-color:hsl(144 8% 96% / var(--tw-bg-opacity, 1))}.hover\\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.hover\\:bg-brand-hover:hover{background-color:var(--brand-hover)}.hover\\:bg-brand\\/40:hover{background-color:hsl(var(--brand-hsl) / .4)}.hover\\:bg-danger-subtle:hover{background-color:hsl(var(--danger-subtle))}.hover\\:bg-danger\\/10:hover{background-color:hsl(var(--danger) / .1)}.hover\\:bg-slate-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.hover\\:bg-slate-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2\\/60:hover{background-color:hsl(var(--surface-2) / .6)}.hover\\:bg-surface-3:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-inset:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.hover\\:bg-transparent:hover{background-color:transparent}.hover\\:bg-white\\/20:hover{background-color:#fff3}.hover\\:text-\\[hsl\\(150_10\\%_12\\%\\)\\]:hover{--tw-text-opacity: 1;color:hsl(150 10% 12% / var(--tw-text-opacity, 1))}.hover\\:text-brand-hover:hover{color:var(--brand-hover)}.hover\\:text-danger:hover{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.hover\\:text-slate-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.hover\\:text-text-primary:hover{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.hover\\:text-text-secondary:hover{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:opacity-90:hover{opacity:.9}.focus\\:border-brand:focus{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.focus\\:bg-surface-2:focus{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus\\:text-text-primary:focus{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus\\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:h-\\[var\\(--issue-sticker-hover-size\\)\\]:focus-visible{height:var(--issue-sticker-hover-size)}.focus-visible\\:max-w-\\[160px\\]:focus-visible{max-width:160px}.focus-visible\\:max-w-\\[480px\\]:focus-visible{max-width:480px}.focus-visible\\:border-line-focus:focus-visible{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.focus-visible\\:border-transparent:focus-visible{border-color:transparent}.focus-visible\\:bg-slate-50:focus-visible{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-1:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-2:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus-visible\\:text-text-primary:focus-visible{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus-visible\\:shadow-focus:focus-visible{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus-visible\\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:outline-line-focus:focus-visible{outline-color:hsl(var(--border-focus) / 1)}.focus-visible\\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-4:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-brand-subtle:focus-visible{--tw-ring-color: var(--brand-subtle)}.focus-visible\\:ring-white\\/40:focus-visible{--tw-ring-color: rgb(255 255 255 / .4)}.active\\:bg-brand-active:active{background-color:var(--brand-active)}.active\\:bg-brand\\/60:active{background-color:hsl(var(--brand-hsl) / .6)}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-40:disabled{opacity:.4}.disabled\\:opacity-50:disabled{opacity:.5}.group\\/marker:hover .group-hover\\/marker\\:h-\\[var\\(--issue-sticker-hover-size\\)\\]{height:var(--issue-sticker-hover-size)}.group\\/marker:hover .group-hover\\/marker\\:max-w-\\[160px\\]{max-width:160px}.group\\/marker:hover .group-hover\\/marker\\:max-w-\\[480px\\]{max-width:480px}.group\\/marker:hover .group-hover\\/marker\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\\/marker:hover .group-hover\\/marker\\:bg-brand-hover{background-color:var(--brand-hover)}.group\\/marker:hover .group-hover\\/marker\\:opacity-100{opacity:1}.group\\/marker:hover .group-hover\\/marker\\:shadow-xl{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.group:focus-visible .group-focus-visible\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:focus-visible .group-focus-visible\\:opacity-100{opacity:1}.group.toaster .group-\\[\\.toaster\\]\\:isolate{isolation:isolate}.group.toast .group-\\[\\.toast\\]\\:rounded-md,.group.toaster .group-\\[\\.toaster\\]\\:rounded-md{border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:border{border-width:1px}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-danger\\/30{border-color:hsl(var(--danger) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-info\\/30{border-color:hsl(var(--info) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-success\\/30{border-color:hsl(var(--success) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-warning\\/30{border-color:hsl(var(--warning) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-danger-subtle{background-color:hsl(var(--danger-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-info-subtle{background-color:hsl(var(--info-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-warning-subtle{background-color:hsl(var(--warning-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:px-4{padding-left:16px;padding-right:16px}.group.toaster .group-\\[\\.toaster\\]\\:py-3{padding-top:12px;padding-bottom:12px}.group.toast .group-\\[\\.toast\\]\\:text-sm{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.group.toast .group-\\[\\.toast\\]\\:text-xs{font-size:clamp(12px,11.69px + .082vw,13px);line-height:1.333}.group.toast .group-\\[\\.toast\\]\\:font-medium{font-weight:500}.group.toast .group-\\[\\.toast\\]\\:text-brand-fg{color:var(--brand-fg)}.group.toast .group-\\[\\.toast\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:absolute:before{content:var(--tw-content);position:absolute}.group.toaster .group-\\[\\.toaster\\]\\:before\\:inset-0:before{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.group.toaster .group-\\[\\.toaster\\]\\:before\\:-z-10:before{content:var(--tw-content);z-index:-10}.group.toaster .group-\\[\\.toaster\\]\\:before\\:rounded-md:before{content:var(--tw-content);border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:bg-surface-1:before{content:var(--tw-content);--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:before\\:content-\\[\\'\\'\\]:before{--tw-content: "";content:var(--tw-content)}.peer:focus-visible~.peer-focus-visible\\:shadow-focus{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.peer:disabled~.peer-disabled\\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\\:opacity-60{opacity:.6}.aria-disabled\\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\\:opacity-40[aria-disabled=true]{opacity:.4}.data-\\[disabled\\]\\:pointer-events-none[data-disabled]{pointer-events:none}@keyframes dialog-out{0%{opacity:1;transform:translate(-50%,-50%) scale(1)}to{opacity:0;transform:translate(-50%,calc(-50% + 8px)) scale(.985)}}.data-\\[state\\=closed\\]\\:animate-dialog-out[data-state=closed]{animation:dialog-out var(--duration-out) var(--ease-out) forwards}@keyframes fade-out{0%{opacity:1}to{opacity:0}}.data-\\[state\\=closed\\]\\:animate-fade-out[data-state=closed]{animation:fade-out var(--duration-out) var(--ease-out) forwards}@keyframes scale-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.97)}}.data-\\[state\\=closed\\]\\:animate-scale-out[data-state=closed]{animation:scale-out var(--duration-out) var(--ease-out) forwards}@keyframes sheet-out-left{0%{transform:translate(0)}to{transform:translate(-100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-left[data-state=closed]{animation:sheet-out-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-out-right{0%{transform:translate(0);opacity:1}to{transform:translate(100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-right[data-state=closed]{animation:sheet-out-right var(--duration-base) var(--ease-out) forwards}.data-\\[state\\=delayed-open\\]\\:animate-scale-in[data-state=delayed-open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes dialog-in{0%{opacity:0;transform:translate(-50%,calc(-50% + 12px)) scale(.985)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}.data-\\[state\\=open\\]\\:animate-dialog-in[data-state=open]{animation:dialog-in var(--duration-base) var(--ease-out) forwards}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.data-\\[state\\=open\\]\\:animate-fade-in[data-state=open]{animation:fade-in var(--duration-base) var(--ease-out) forwards}@keyframes scale-in{0%{opacity:0;transform:scale(.98)}to{opacity:1;transform:scale(1)}}.data-\\[state\\=open\\]\\:animate-scale-in[data-state=open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-left{0%{transform:translate(-100%);opacity:.6}to{transform:translate(0);opacity:1}}.data-\\[state\\=open\\]\\:animate-sheet-in-left[data-state=open]{animation:sheet-in-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-right{0%{transform:translate(100%);opacity:.6}to{transform:translate(0)}}.data-\\[state\\=open\\]\\:animate-sheet-in-right[data-state=open]{animation:sheet-in-right var(--duration-base) var(--ease-out) forwards}.data-\\[range-end\\=true\\]\\:rounded-md[data-range-end=true]{border-radius:var(--radius-md)}.data-\\[range-middle\\=true\\]\\:rounded-none[data-range-middle=true]{border-radius:0}.data-\\[range-start\\=true\\]\\:rounded-md[data-range-start=true]{border-radius:var(--radius-md)}.data-\\[state\\=open\\]\\:border-line-focus[data-state=open]{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.data-\\[highlighted\\]\\:bg-surface-2[data-highlighted]{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.data-\\[range-end\\=true\\]\\:bg-brand[data-range-end=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[range-middle\\=true\\]\\:bg-transparent[data-range-middle=true]{background-color:transparent}.data-\\[range-start\\=true\\]\\:bg-brand[data-range-start=true],.data-\\[selected-single\\=true\\]\\:bg-brand[data-selected-single=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[state\\=selected\\]\\:bg-brand-subtle[data-state=selected]{background-color:var(--brand-subtle)}.data-\\[today\\=true\\]\\:font-semibold[data-today=true]{font-weight:600}.data-\\[highlighted\\]\\:text-text-primary[data-highlighted]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[placeholder\\]\\:text-text-tertiary[data-placeholder]{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.data-\\[range-end\\=true\\]\\:text-brand-fg[data-range-end=true]{color:var(--brand-fg)}.data-\\[range-middle\\=true\\]\\:text-text-primary[data-range-middle=true]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[range-start\\=true\\]\\:text-brand-fg[data-range-start=true],.data-\\[selected-single\\=true\\]\\:text-brand-fg[data-selected-single=true]{color:var(--brand-fg)}.data-\\[state\\=active\\]\\:text-text-primary[data-state=active],.data-\\[state\\=checked\\]\\:text-text-primary[data-state=checked]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[today\\=true\\]\\:text-brand[data-today=true]{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.data-\\[disabled\\]\\:opacity-50[data-disabled]{opacity:.5}.data-\\[state\\=open\\]\\:shadow-focus[data-state=open]{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\\[range-end\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:bg-brand-hover:hover[data-selected-single=true]{background-color:var(--brand-hover)}.data-\\[range-end\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:text-brand-fg:hover[data-selected-single=true]{color:var(--brand-fg)}@media(prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}}@media(min-width:640px){.sm\\:flex-row{flex-direction:row}.sm\\:items-start{align-items:flex-start}.sm\\:items-center{align-items:center}.sm\\:justify-end{justify-content:flex-end}.sm\\:justify-between{justify-content:space-between}.sm\\:gap-2\\.5{gap:10px}.sm\\:p-5{padding:20px}.sm\\:p-6{padding:24px}.sm\\:text-2xl{font-size:clamp(26px,24.78px + .327vw,30px);line-height:1.308}.sm\\:text-\\[2\\.1rem\\]{font-size:33.6px}}@media(min-width:768px){.md\\:flex{display:flex}.md\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\\:grid-cols-\\[minmax\\(0\\,1fr\\)_minmax\\(260px\\,340px\\)\\]{grid-template-columns:minmax(0,1fr) minmax(260px,340px)}}.\\[\\&\\>\\*\\:not\\(summary\\)\\]\\:pl-4>*:not(summary){padding-left:16px}.\\[\\&\\>span\\]\\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\\[\\&\\>tr\\]\\:last\\:border-b-0:last-child>tr{border-bottom-width:0px}.\\[\\&\\[data-state\\=open\\]\\>span\\[data-chevron\\]\\]\\:rotate-180[data-state=open]>span[data-chevron]{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-danger [data-icon]{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-info [data-icon]{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-success [data-icon]{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-warning [data-icon]{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.\\[\\&_tr\\]\\:border-b tr{border-bottom-width:1px}.\\[\\&_tr\\]\\:border-line-subtle tr{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}li .\\[li_\\&\\]\\:pl-5{padding-left:20px}`;
|
|
39888
40250
|
const sdkShadowCSS = ".issue-sticker-marker{pointer-events:auto}@keyframes highlight-pulse{0%,to{transform:scale(1);box-shadow:var(--shadow-md)}50%{transform:scale(1.3);box-shadow:var(--shadow-focus),var(--shadow-lg)}}.issue-sticker-marker.highlight-animation{animation:highlight-pulse .7s ease-in-out 3}";
|
|
39889
40251
|
const contentPageCSS = `@layer issue-sticker-mode{html:has(>body.issue-sticker-mode-active),body.issue-sticker-mode-active,body.issue-sticker-mode-active *{cursor:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cpath d='M3 29 C3 22 3 20 3 15 a12 12 0 0 1 12-12 h2 a12 12 0 0 1 12 12 a12 12 0 0 1-12 12 H12 Z' fill='%231C221F' fill-opacity='0.35' stroke='%23ffffff' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E") 3 29,crosshair!important}body.issue-sticker-mode-active iframe{pointer-events:none!important}body.issue-sticker-mode-active .issue-sticker-mode-highlight{outline:2px solid hsl(160 64% 34%)!important;outline-offset:2px!important;background-color:#1f8e691f!important;transition:outline .1s ease,background-color .1s ease!important}}`;
|
|
39890
40252
|
const PAGE_STYLE_ID = "issue-sticker-page-style";
|
|
39891
40253
|
let root = null;
|
|
39892
40254
|
let mountContainer = null;
|
|
40255
|
+
let detachHostGuards = null;
|
|
39893
40256
|
function renderWidget(config) {
|
|
39894
40257
|
if (!root || !mountContainer) {
|
|
39895
40258
|
return;
|
|
@@ -39920,9 +40283,13 @@ function mountWidget(config) {
|
|
|
39920
40283
|
}
|
|
39921
40284
|
document.body.appendChild(hostElement);
|
|
39922
40285
|
const shadow = createShadowRoot(hostElement, [globalsCSS, sdkShadowCSS]);
|
|
39923
|
-
|
|
39924
|
-
|
|
39925
|
-
|
|
40286
|
+
detachHostGuards == null ? void 0 : detachHostGuards();
|
|
40287
|
+
const guards = [
|
|
40288
|
+
attachHostTypingGuard(shadow.shadowRoot),
|
|
40289
|
+
attachHostPointerGuard(shadow.shadowRoot),
|
|
40290
|
+
attachHostInteractionGuard(shadow.shadowRoot)
|
|
40291
|
+
];
|
|
40292
|
+
detachHostGuards = () => guards.forEach((detach) => detach());
|
|
39926
40293
|
mountContainer = shadow.mountContainer;
|
|
39927
40294
|
mountContainer.style.width = "0";
|
|
39928
40295
|
mountContainer.style.height = "0";
|
|
@@ -39938,6 +40305,8 @@ function unmountWidget() {
|
|
|
39938
40305
|
root = null;
|
|
39939
40306
|
}
|
|
39940
40307
|
mountContainer = null;
|
|
40308
|
+
detachHostGuards == null ? void 0 : detachHostGuards();
|
|
40309
|
+
detachHostGuards = null;
|
|
39941
40310
|
const host = document.getElementById(ISSUE_STICKER_HOST_ELEMENT_ID);
|
|
39942
40311
|
if (host && getIssueStickerRuntimeOwner(host) !== ISSUE_STICKER_RUNTIME_OWNER.extension) {
|
|
39943
40312
|
host.remove();
|