issue-sticker 0.12.0 → 0.13.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 +46 -0
- package/dist/{externalUserPayload-DWcXyz2U.js → externalUserPayload-CdzgCq4t.js} +10453 -7486
- package/dist/issue-sticker-headless-react.js +68 -12
- package/dist/issue-sticker-headless.js +457 -95
- package/dist/issue-sticker-react.js +1431 -400
- package/dist/{three-B228j4M6.js → three-FamoZZKK.js} +560 -33
- package/dist/{tooltip-CT7e9xbU.js → tooltip-BVA6ikuJ.js} +1 -1
- package/headless.d.ts +35 -4
- package/package.json +1 -1
|
@@ -15,21 +15,97 @@ 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,
|
|
19
|
-
import {
|
|
18
|
+
import { M as MASKING_COPY, O as OVERLAY_LAYER_INDEX, c as createLucideIcon$1, h as usePortalContainer, e as cn$1, i as OVERLAY_LAYER, s as stopEscapePropagation, j as useControllableState, k as useId$1, P as Presence, l as Primitive, m as composeEventHandlers, n as useDismissableLayerSurface, o as useComposedRefs$1, p as Portal$1, q as createContextScope, t as createSlot, D as DismissableLayer, v as useLayoutEffect2, w as useCallbackRef, u as ungzip_1, x as PortalContainerProvider, r as registerThree } from "./three-FamoZZKK.js";
|
|
19
|
+
import { a8 as toast, a9 as MASKING_NOTICE_TOAST_DURATION_MS, aa as trimLogBackupPayload, ab as createSafeLogBackup, ac as getLogBackupSessionId, N as NetworkCollector, C as ConsoleCollector, W as WebSocketCollector, ad as createIndexedDbLogBackup, e as buildJiraCreateFields, ae as Popover, af as PopoverTrigger, ag as Input, ah as PopoverContent, ai as Label, aj as Select, ak as SelectTrigger, al as SelectValue, am as SelectContent, an as SelectItem, ao as JIRA_ISSUE_TYPE_VALUE_KEY, ap as getJiraMetadata, aq as buildJiraIssueFields, ar as getJiraIssueTypeLabel, as as Button, at as Root2$2, au as Trigger$2, av as ChevronDown, aw as Portal, ax as Content2$1, ay as Check, az as X$1, aA as DatePicker, f as buildNotionCreateFields, aB as getNotionPageMetadata, aC as buildNotionFieldViews, b as captureScreenshotWithMasks, p as pristineFetch, d as directUploadToSignedUrl, aD as DirectUploadError, a as uploadSignedMediaWithApi, w as sanitizeString, aE as getRegisteredUploadId, h as buildGuestOwnerQuery, Q as createIssueUploadQueues, a2 as loadTusClient, a3 as createIndexedDbPendingUploadStore, a6 as createMediaUploadApi, a4 as ATTACHMENT_UPLOAD_DB_NAME, a5 as VIDEO_UPLOAD_DB_NAME, a1 as createMaskingPolicySource, a7 as createMemoryMaskingPolicyCache, Y as MASKING_POLICY_PREFETCH_TIMEOUT_MS, aF as getSnapshot, aG as subscribe$1, l as devLogger, P as getCurrentPageUrl, aH as ChevronRight, aI as ReactRemoveScroll, aJ as hideOthers, aK as useFocusGuards, aL as FocusScope, aM as createShadowDismissRoot, aN as getExposedJiraFields, aO as isJiraFieldExposed, aP as normalizeExposedJiraFields, u as uploadScreenshotDataUrls, c as captureViewportAndElementShots, M as MaskingCaptureError, T as preloadModernScreenshot, g as getElementPosition, _ as loadCaptureSelectors, i as isCapturedScreenshot, F as collectSnapshotSelectors, G as MaskingScreenRulesChangedError, K as assertScreenRulesCovered, L as isMaskingFailure, O as maskScreenshotsForSubmit, aQ as NO_MASKING_OUTCOME, aR as describeMaskingSubmitFailure, m as filterExcludeServiceRelatedLogs, n as filterExcludeServiceRelatedConsoleLogs, s as selectNetworkLogsForSubmit, o as compactNetworkLogsForTransport, q as CONSOLE_LOG_SUBMIT_LIMIT, k as buildIssueIntegrationsPayload, x as runMaskedSubmit, y as applySubmitMasking, r as buildExternalUserPayload, A as maskPositionForSubmit, D as appendMaskingNotice, E as screenshotExclusionNotice, z as collectAttachmentUploads, B as hasReplayUpload, t as shrinkNetworkLogsToFit, v as measureJsonBytes, U as enqueueIssueUploads, V as normalizeUploadMimeType, R as SessionReplayCaptureController, aS as resolveJiraIssueTypeId, aT as pickJiraIssueTypeFields, aU as switchJiraIssueType, a0 as resolveEffectivePolicy, $ as loadMaskingPolicyForSubmit, aV as getPrimaryNotionMapping, aW as getPrimaryJiraMapping, aX as createCollection, aY as useDirection, aZ as useShadowOutsideDismiss, a_ as buttonVariants, a$ as TEST_ATTR_KEYS, b0 as jaccard, b1 as textSimilarity, b2 as collectHeadings, b3 as buildElementLocator, b4 as normalizeForCompare, b5 as CONTAINER_SELECTOR, b6 as safeRole, b7 as safeAccessibleName, b8 as sameDigitGroups, b9 as labelSimilarityKeepingDigits, ba as landmarkRole, bb as findElementBySelector, bc as findElementByXPath, S as ScreenRecordingController, bd as maskingCompletionNotice, j as composeIssueFilterGroups, be as OnboardingProvider, bf as useOnboardingTarget, bg as useOnboardingFlow, bh as PopoverAnchor } from "./externalUserPayload-CdzgCq4t.js";
|
|
20
20
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
21
21
|
import * as React from "react";
|
|
22
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";
|
|
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-
|
|
25
|
+
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-BVA6ikuJ.js";
|
|
26
26
|
import { g as getDefaultExportFromCjs } from "./_commonjsHelpers-DWwsNxpa.js";
|
|
27
|
+
function debounce(func, debounceMs, { signal, edges } = {}) {
|
|
28
|
+
let pendingThis = void 0;
|
|
29
|
+
let pendingArgs = null;
|
|
30
|
+
const leading = edges != null && edges.includes("leading");
|
|
31
|
+
const trailing = edges == null || edges.includes("trailing");
|
|
32
|
+
const invoke = () => {
|
|
33
|
+
if (pendingArgs !== null) {
|
|
34
|
+
func.apply(pendingThis, pendingArgs);
|
|
35
|
+
pendingThis = void 0;
|
|
36
|
+
pendingArgs = null;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const onTimerEnd = () => {
|
|
40
|
+
if (trailing) invoke();
|
|
41
|
+
cancel();
|
|
42
|
+
};
|
|
43
|
+
let timeoutId = null;
|
|
44
|
+
const schedule = () => {
|
|
45
|
+
if (timeoutId != null) clearTimeout(timeoutId);
|
|
46
|
+
timeoutId = setTimeout(() => {
|
|
47
|
+
timeoutId = null;
|
|
48
|
+
onTimerEnd();
|
|
49
|
+
}, debounceMs);
|
|
50
|
+
};
|
|
51
|
+
const cancelTimer = () => {
|
|
52
|
+
if (timeoutId !== null) {
|
|
53
|
+
clearTimeout(timeoutId);
|
|
54
|
+
timeoutId = null;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const cancel = () => {
|
|
58
|
+
cancelTimer();
|
|
59
|
+
pendingThis = void 0;
|
|
60
|
+
pendingArgs = null;
|
|
61
|
+
};
|
|
62
|
+
const flush = () => {
|
|
63
|
+
invoke();
|
|
64
|
+
};
|
|
65
|
+
const debounced = function(...args) {
|
|
66
|
+
if (signal == null ? void 0 : signal.aborted) return;
|
|
67
|
+
pendingThis = this;
|
|
68
|
+
pendingArgs = args;
|
|
69
|
+
const isFirstCall = timeoutId == null;
|
|
70
|
+
schedule();
|
|
71
|
+
if (leading && isFirstCall) invoke();
|
|
72
|
+
};
|
|
73
|
+
debounced.schedule = schedule;
|
|
74
|
+
debounced.cancel = cancel;
|
|
75
|
+
debounced.flush = flush;
|
|
76
|
+
signal == null ? void 0 : signal.addEventListener("abort", cancel, { once: true });
|
|
77
|
+
return debounced;
|
|
78
|
+
}
|
|
79
|
+
function throttle(func, throttleMs, { signal, edges = ["leading", "trailing"] } = {}) {
|
|
80
|
+
let pendingAt = null;
|
|
81
|
+
const debounced = debounce(function(...args) {
|
|
82
|
+
pendingAt = Date.now();
|
|
83
|
+
func.apply(this, args);
|
|
84
|
+
}, throttleMs, {
|
|
85
|
+
signal,
|
|
86
|
+
edges
|
|
87
|
+
});
|
|
88
|
+
const throttled = function(...args) {
|
|
89
|
+
if (pendingAt == null) pendingAt = Date.now();
|
|
90
|
+
if (Date.now() - pendingAt >= throttleMs) {
|
|
91
|
+
pendingAt = Date.now();
|
|
92
|
+
func.apply(this, args);
|
|
93
|
+
debounced.cancel();
|
|
94
|
+
debounced.schedule();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
debounced.apply(this, args);
|
|
98
|
+
};
|
|
99
|
+
throttled.cancel = debounced.cancel;
|
|
100
|
+
throttled.flush = debounced.flush;
|
|
101
|
+
return throttled;
|
|
102
|
+
}
|
|
27
103
|
const ISSUE_STICKER_REPORT_FORM_CLASS = "issue-sticker-report-form";
|
|
28
104
|
function summarizeVideoUploads(states) {
|
|
29
105
|
if (states.length === 0) return void 0;
|
|
30
106
|
const remaining = states.filter((state) => state.status !== "failed");
|
|
31
|
-
const
|
|
32
|
-
const percent2 =
|
|
107
|
+
const current2 = states.find((state) => state.status === "uploading");
|
|
108
|
+
const percent2 = current2 && current2.bytesTotal > 0 ? Math.floor(current2.bytesSent / current2.bytesTotal * 100) : 0;
|
|
33
109
|
return { percent: percent2, count: remaining.length, failed: remaining.length === 0 };
|
|
34
110
|
}
|
|
35
111
|
const VIDEO_UPLOAD_COPY = {
|
|
@@ -66,6 +142,7 @@ function createIssueUploadToaster() {
|
|
|
66
142
|
const failureToastIds = /* @__PURE__ */ new Map();
|
|
67
143
|
return {
|
|
68
144
|
show(notice, retry) {
|
|
145
|
+
var _a;
|
|
69
146
|
const previous2 = failureToastIds.get(notice.issueId);
|
|
70
147
|
if (previous2 !== void 0) {
|
|
71
148
|
toast.dismiss(previous2);
|
|
@@ -87,7 +164,13 @@ function createIssueUploadToaster() {
|
|
|
87
164
|
failureToastIds.set(notice.issueId, id2);
|
|
88
165
|
return;
|
|
89
166
|
}
|
|
90
|
-
|
|
167
|
+
let aborted = visibleKinds(notice.aborted);
|
|
168
|
+
if (((_a = notice.abortReasons) == null ? void 0 : _a.video) === "masking_video_excluded") {
|
|
169
|
+
toast.warning(MASKING_COPY.videoExcludedAfterCreate, {
|
|
170
|
+
duration: MASKING_NOTICE_TOAST_DURATION_MS
|
|
171
|
+
});
|
|
172
|
+
aborted = aborted === "both" ? "replay" : null;
|
|
173
|
+
}
|
|
91
174
|
if (aborted) {
|
|
92
175
|
toast.error(ISSUE_UPLOAD_COPY.aborted[aborted], {
|
|
93
176
|
title: ISSUE_UPLOAD_COPY.failedTitle[aborted]
|
|
@@ -292,82 +375,6 @@ function getIntegrationFailureMessage(service) {
|
|
|
292
375
|
const action = FAILED_ACTION_TEXT[service] ?? "연동 작업을 마치지 못했습니다.";
|
|
293
376
|
return `이슈는 저장했지만 ${action}`;
|
|
294
377
|
}
|
|
295
|
-
function debounce(func, debounceMs, { signal, edges } = {}) {
|
|
296
|
-
let pendingThis = void 0;
|
|
297
|
-
let pendingArgs = null;
|
|
298
|
-
const leading = edges != null && edges.includes("leading");
|
|
299
|
-
const trailing = edges == null || edges.includes("trailing");
|
|
300
|
-
const invoke = () => {
|
|
301
|
-
if (pendingArgs !== null) {
|
|
302
|
-
func.apply(pendingThis, pendingArgs);
|
|
303
|
-
pendingThis = void 0;
|
|
304
|
-
pendingArgs = null;
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
const onTimerEnd = () => {
|
|
308
|
-
if (trailing) invoke();
|
|
309
|
-
cancel();
|
|
310
|
-
};
|
|
311
|
-
let timeoutId = null;
|
|
312
|
-
const schedule = () => {
|
|
313
|
-
if (timeoutId != null) clearTimeout(timeoutId);
|
|
314
|
-
timeoutId = setTimeout(() => {
|
|
315
|
-
timeoutId = null;
|
|
316
|
-
onTimerEnd();
|
|
317
|
-
}, debounceMs);
|
|
318
|
-
};
|
|
319
|
-
const cancelTimer = () => {
|
|
320
|
-
if (timeoutId !== null) {
|
|
321
|
-
clearTimeout(timeoutId);
|
|
322
|
-
timeoutId = null;
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
const cancel = () => {
|
|
326
|
-
cancelTimer();
|
|
327
|
-
pendingThis = void 0;
|
|
328
|
-
pendingArgs = null;
|
|
329
|
-
};
|
|
330
|
-
const flush = () => {
|
|
331
|
-
invoke();
|
|
332
|
-
};
|
|
333
|
-
const debounced = function(...args) {
|
|
334
|
-
if (signal == null ? void 0 : signal.aborted) return;
|
|
335
|
-
pendingThis = this;
|
|
336
|
-
pendingArgs = args;
|
|
337
|
-
const isFirstCall = timeoutId == null;
|
|
338
|
-
schedule();
|
|
339
|
-
if (leading && isFirstCall) invoke();
|
|
340
|
-
};
|
|
341
|
-
debounced.schedule = schedule;
|
|
342
|
-
debounced.cancel = cancel;
|
|
343
|
-
debounced.flush = flush;
|
|
344
|
-
signal == null ? void 0 : signal.addEventListener("abort", cancel, { once: true });
|
|
345
|
-
return debounced;
|
|
346
|
-
}
|
|
347
|
-
function throttle(func, throttleMs, { signal, edges = ["leading", "trailing"] } = {}) {
|
|
348
|
-
let pendingAt = null;
|
|
349
|
-
const debounced = debounce(function(...args) {
|
|
350
|
-
pendingAt = Date.now();
|
|
351
|
-
func.apply(this, args);
|
|
352
|
-
}, throttleMs, {
|
|
353
|
-
signal,
|
|
354
|
-
edges
|
|
355
|
-
});
|
|
356
|
-
const throttled = function(...args) {
|
|
357
|
-
if (pendingAt == null) pendingAt = Date.now();
|
|
358
|
-
if (Date.now() - pendingAt >= throttleMs) {
|
|
359
|
-
pendingAt = Date.now();
|
|
360
|
-
func.apply(this, args);
|
|
361
|
-
debounced.cancel();
|
|
362
|
-
debounced.schedule();
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
debounced.apply(this, args);
|
|
366
|
-
};
|
|
367
|
-
throttled.cancel = debounced.cancel;
|
|
368
|
-
throttled.flush = debounced.flush;
|
|
369
|
-
return throttled;
|
|
370
|
-
}
|
|
371
378
|
function getJiraFieldDefaultValues(exposedFields, fieldDefinitions = []) {
|
|
372
379
|
const values = {};
|
|
373
380
|
for (const field of buildJiraCreateFields(exposedFields, fieldDefinitions)) {
|
|
@@ -1060,6 +1067,17 @@ const EllipsisVertical = createLucideIcon$1("EllipsisVertical", [
|
|
|
1060
1067
|
["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
|
|
1061
1068
|
["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
|
|
1062
1069
|
]);
|
|
1070
|
+
/**
|
|
1071
|
+
* @license lucide-react v0.468.0 - ISC
|
|
1072
|
+
*
|
|
1073
|
+
* This source code is licensed under the ISC license.
|
|
1074
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1075
|
+
*/
|
|
1076
|
+
const ExternalLink$1 = createLucideIcon$1("ExternalLink", [
|
|
1077
|
+
["path", { d: "M15 3h6v6", key: "1q9fwt" }],
|
|
1078
|
+
["path", { d: "M10 14 21 3", key: "gplh6r" }],
|
|
1079
|
+
["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
|
|
1080
|
+
]);
|
|
1063
1081
|
/**
|
|
1064
1082
|
* @license lucide-react v0.468.0 - ISC
|
|
1065
1083
|
*
|
|
@@ -1150,6 +1168,16 @@ const LocateFixed = createLucideIcon$1("LocateFixed", [
|
|
|
1150
1168
|
["circle", { cx: "12", cy: "12", r: "7", key: "fim9np" }],
|
|
1151
1169
|
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
1152
1170
|
]);
|
|
1171
|
+
/**
|
|
1172
|
+
* @license lucide-react v0.468.0 - ISC
|
|
1173
|
+
*
|
|
1174
|
+
* This source code is licensed under the ISC license.
|
|
1175
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1176
|
+
*/
|
|
1177
|
+
const Lock = createLucideIcon$1("Lock", [
|
|
1178
|
+
["rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2", key: "1w4ew1" }],
|
|
1179
|
+
["path", { d: "M7 11V7a5 5 0 0 1 10 0v4", key: "fwvmzm" }]
|
|
1180
|
+
]);
|
|
1153
1181
|
/**
|
|
1154
1182
|
* @license lucide-react v0.468.0 - ISC
|
|
1155
1183
|
*
|
|
@@ -3863,8 +3891,8 @@ var QueryObserver = (_g = class extends Subscribable {
|
|
|
3863
3891
|
}
|
|
3864
3892
|
};
|
|
3865
3893
|
const recreateThenable = () => {
|
|
3866
|
-
const
|
|
3867
|
-
finalizeThenableIfPossible(
|
|
3894
|
+
const pending2 = __privateSet(this, _currentThenable, nextResult.promise = pendingThenable());
|
|
3895
|
+
finalizeThenableIfPossible(pending2);
|
|
3868
3896
|
};
|
|
3869
3897
|
const prevThenable = __privateGet(this, _currentThenable);
|
|
3870
3898
|
switch (prevThenable.status) {
|
|
@@ -5204,6 +5232,231 @@ function useGuardedCallback(callback) {
|
|
|
5204
5232
|
}, []);
|
|
5205
5233
|
return { execute, isExecuting, reset };
|
|
5206
5234
|
}
|
|
5235
|
+
function isSyncService(value) {
|
|
5236
|
+
return value === "JIRA" || value === "NOTION";
|
|
5237
|
+
}
|
|
5238
|
+
function readUnsupported(metadata) {
|
|
5239
|
+
if (typeof metadata !== "object" || metadata === null) return [];
|
|
5240
|
+
const sync = metadata.description_sync;
|
|
5241
|
+
if (typeof sync !== "object" || sync === null) return [];
|
|
5242
|
+
const list2 = sync.unsupported;
|
|
5243
|
+
if (!Array.isArray(list2)) return [];
|
|
5244
|
+
return list2.filter(
|
|
5245
|
+
(e) => typeof (e == null ? void 0 : e.type) === "string" && typeof (e == null ? void 0 : e.count) === "number"
|
|
5246
|
+
);
|
|
5247
|
+
}
|
|
5248
|
+
function readDescriptionSyncLock(mappings) {
|
|
5249
|
+
for (const mapping of mappings ?? []) {
|
|
5250
|
+
if (!isSyncService(mapping.service_type)) continue;
|
|
5251
|
+
const elements = readUnsupported(mapping.metadata);
|
|
5252
|
+
if (elements.length === 0) continue;
|
|
5253
|
+
return {
|
|
5254
|
+
serviceType: mapping.service_type,
|
|
5255
|
+
blocksEditing: elements.some((e) => e.type === "anchor_missing"),
|
|
5256
|
+
elements
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5259
|
+
return null;
|
|
5260
|
+
}
|
|
5261
|
+
function isHiddenBlock(value) {
|
|
5262
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5263
|
+
const { markdown, kinds, viewable } = value;
|
|
5264
|
+
return typeof markdown === "string" && Array.isArray(kinds) && kinds.every((kind) => typeof kind === "string") && typeof viewable === "boolean";
|
|
5265
|
+
}
|
|
5266
|
+
function readHidden(metadata) {
|
|
5267
|
+
if (typeof metadata !== "object" || metadata === null) return void 0;
|
|
5268
|
+
const sync = metadata.description_sync;
|
|
5269
|
+
if (typeof sync !== "object" || sync === null) return void 0;
|
|
5270
|
+
const hidden = sync.hidden;
|
|
5271
|
+
return Array.isArray(hidden) && hidden.every(isHiddenBlock) ? hidden : void 0;
|
|
5272
|
+
}
|
|
5273
|
+
const BLOCK_SEPARATOR = "\n\n";
|
|
5274
|
+
function removeHidden(description, hidden) {
|
|
5275
|
+
let out = description;
|
|
5276
|
+
let from = 0;
|
|
5277
|
+
const cuts = [];
|
|
5278
|
+
const atBoundary = (start, end) => (start === 0 || out.startsWith(BLOCK_SEPARATOR, start - BLOCK_SEPARATOR.length)) && (end === out.length || out.startsWith(BLOCK_SEPARATOR, end));
|
|
5279
|
+
for (const block of hidden) {
|
|
5280
|
+
const piece = block.markdown;
|
|
5281
|
+
if (!piece) continue;
|
|
5282
|
+
let start = out.indexOf(piece, from);
|
|
5283
|
+
while (start !== -1 && !atBoundary(start, start + piece.length)) {
|
|
5284
|
+
const next = start + 1 > out.length ? -1 : out.indexOf(piece, start + 1);
|
|
5285
|
+
start = next > start ? next : -1;
|
|
5286
|
+
}
|
|
5287
|
+
if (start === -1) return null;
|
|
5288
|
+
let end = start + piece.length;
|
|
5289
|
+
if (out.startsWith(BLOCK_SEPARATOR, end)) end += BLOCK_SEPARATOR.length;
|
|
5290
|
+
else if (start >= BLOCK_SEPARATOR.length && out.startsWith(BLOCK_SEPARATOR, start - BLOCK_SEPARATOR.length)) {
|
|
5291
|
+
start -= BLOCK_SEPARATOR.length;
|
|
5292
|
+
}
|
|
5293
|
+
out = out.slice(0, start) + out.slice(end);
|
|
5294
|
+
for (const cut of cuts) cut.at = Math.min(cut.at, start);
|
|
5295
|
+
cuts.push({ block, at: start });
|
|
5296
|
+
from = start;
|
|
5297
|
+
}
|
|
5298
|
+
const lead = out.length - out.trimStart().length;
|
|
5299
|
+
const text2 = out.trim();
|
|
5300
|
+
for (const cut of cuts) cut.at = Math.min(Math.max(cut.at - lead, 0), text2.length);
|
|
5301
|
+
return { text: text2, cuts };
|
|
5302
|
+
}
|
|
5303
|
+
function trimBlankLines(markdown) {
|
|
5304
|
+
return markdown.replace(/^(?:[ \t]*\n)+/, "").replace(/(?:\n[ \t]*)+$/, "");
|
|
5305
|
+
}
|
|
5306
|
+
function splitDescription(description, hidden) {
|
|
5307
|
+
const removed = removeHidden(description, hidden);
|
|
5308
|
+
if (!removed) return null;
|
|
5309
|
+
const { text: text2, cuts } = removed;
|
|
5310
|
+
const pieces = [];
|
|
5311
|
+
const pushText2 = (slice) => {
|
|
5312
|
+
const markdown = trimBlankLines(slice);
|
|
5313
|
+
if (markdown.trim()) pieces.push({ kind: "text", markdown });
|
|
5314
|
+
};
|
|
5315
|
+
let prev = 0;
|
|
5316
|
+
for (const { block, at } of cuts) {
|
|
5317
|
+
pushText2(text2.slice(prev, at));
|
|
5318
|
+
pieces.push({ kind: "hidden", block });
|
|
5319
|
+
prev = at;
|
|
5320
|
+
}
|
|
5321
|
+
pushText2(text2.slice(prev));
|
|
5322
|
+
return pieces;
|
|
5323
|
+
}
|
|
5324
|
+
function editableDescription(description, hidden) {
|
|
5325
|
+
var _a;
|
|
5326
|
+
return ((_a = removeHidden(description, hidden)) == null ? void 0 : _a.text) ?? null;
|
|
5327
|
+
}
|
|
5328
|
+
function editBasisOf(view, description) {
|
|
5329
|
+
const blocks = ((view == null ? void 0 : view.pieces) ?? []).flatMap(
|
|
5330
|
+
(piece) => piece.kind === "hidden" ? [piece.block] : []
|
|
5331
|
+
);
|
|
5332
|
+
if (blocks.length === 0) return [];
|
|
5333
|
+
return editableDescription(description ?? "", blocks) === null ? [] : blocks.map((block) => block.markdown);
|
|
5334
|
+
}
|
|
5335
|
+
function descriptionStateSignature(view, description) {
|
|
5336
|
+
return JSON.stringify([
|
|
5337
|
+
(view == null ? void 0 : view.serviceType) ?? null,
|
|
5338
|
+
editBasisOf(view, description),
|
|
5339
|
+
!!(view == null ? void 0 : view.needsRefresh)
|
|
5340
|
+
]);
|
|
5341
|
+
}
|
|
5342
|
+
function isSaveRejectionRepeating(sent, fresh) {
|
|
5343
|
+
if ((fresh.description ?? "") !== (sent.description ?? "")) return false;
|
|
5344
|
+
const freshBasis = editBasisOf(
|
|
5345
|
+
readDescriptionView(fresh.issue_external_mappings, fresh.description),
|
|
5346
|
+
fresh.description
|
|
5347
|
+
);
|
|
5348
|
+
return freshBasis.length === sent.basis.length && freshBasis.every((markdown, index2) => markdown === sent.basis[index2]);
|
|
5349
|
+
}
|
|
5350
|
+
function collectHiddenKinds(pieces) {
|
|
5351
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
5352
|
+
for (const piece of pieces) {
|
|
5353
|
+
if (piece.kind === "hidden") for (const kind of piece.block.kinds) kinds.add(kind);
|
|
5354
|
+
}
|
|
5355
|
+
return [...kinds];
|
|
5356
|
+
}
|
|
5357
|
+
function readDescriptionView(mappings, description) {
|
|
5358
|
+
for (const mapping of mappings ?? []) {
|
|
5359
|
+
if (!isSyncService(mapping.service_type)) continue;
|
|
5360
|
+
const unsupported = readUnsupported(mapping.metadata);
|
|
5361
|
+
const hidden = readHidden(mapping.metadata);
|
|
5362
|
+
if (unsupported.length === 0 && !(hidden == null ? void 0 : hidden.length)) continue;
|
|
5363
|
+
const pieces = hidden ? splitDescription(description ?? "", hidden) : null;
|
|
5364
|
+
return {
|
|
5365
|
+
serviceType: mapping.service_type,
|
|
5366
|
+
pieces,
|
|
5367
|
+
// 조각을 못 만들었을 때: 위치를 못 찾은 hidden 이 있거나, hidden 없이 anchor_missing 밖
|
|
5368
|
+
// 보호 요소만 있으면 편집란이 숨길 곳을 모른다.
|
|
5369
|
+
needsRefresh: pieces === null && (!!(hidden == null ? void 0 : hidden.length) || unsupported.some((e) => e.type !== "anchor_missing"))
|
|
5370
|
+
};
|
|
5371
|
+
}
|
|
5372
|
+
return null;
|
|
5373
|
+
}
|
|
5374
|
+
const ELEMENT_NAMES = {
|
|
5375
|
+
panel: "패널",
|
|
5376
|
+
expand: "접기 블록",
|
|
5377
|
+
nestedExpand: "접기 블록",
|
|
5378
|
+
mediaSingle: "첨부 이미지·파일",
|
|
5379
|
+
mediaGroup: "첨부 이미지·파일",
|
|
5380
|
+
media: "첨부 이미지·파일",
|
|
5381
|
+
mediaInline: "첨부 이미지·파일",
|
|
5382
|
+
mention: "멘션",
|
|
5383
|
+
status: "상태 라벨",
|
|
5384
|
+
date: "날짜",
|
|
5385
|
+
emoji: "이모지",
|
|
5386
|
+
blockTaskItem: "체크리스트 항목",
|
|
5387
|
+
syncBlock: "동기화 블록",
|
|
5388
|
+
bodiedSyncBlock: "동기화 블록",
|
|
5389
|
+
textColor: "글자색",
|
|
5390
|
+
underline: "밑줄",
|
|
5391
|
+
subsup: "위첨자·아래첨자",
|
|
5392
|
+
border: "테두리",
|
|
5393
|
+
backgroundColor: "배경색",
|
|
5394
|
+
decisionList: "의사결정 목록",
|
|
5395
|
+
layoutSection: "다단 레이아웃",
|
|
5396
|
+
table: "표",
|
|
5397
|
+
blockCard: "링크 카드",
|
|
5398
|
+
embedCard: "임베드",
|
|
5399
|
+
extension: "매크로",
|
|
5400
|
+
bodiedExtension: "매크로",
|
|
5401
|
+
multiBodiedExtension: "매크로",
|
|
5402
|
+
inlineExtension: "매크로",
|
|
5403
|
+
anchor_missing: "지워진 설명 섹션 제목",
|
|
5404
|
+
// Notion 블록 타입
|
|
5405
|
+
callout: "콜아웃",
|
|
5406
|
+
image: "첨부 이미지·파일",
|
|
5407
|
+
video: "첨부 이미지·파일",
|
|
5408
|
+
audio: "첨부 이미지·파일",
|
|
5409
|
+
file: "첨부 이미지·파일",
|
|
5410
|
+
pdf: "첨부 이미지·파일",
|
|
5411
|
+
bookmark: "북마크",
|
|
5412
|
+
embed: "임베드",
|
|
5413
|
+
column_list: "다단 레이아웃",
|
|
5414
|
+
table_of_contents: "목차",
|
|
5415
|
+
toggle_heading: "토글 제목",
|
|
5416
|
+
synced_block: "동기화 블록",
|
|
5417
|
+
child_page: "하위 페이지",
|
|
5418
|
+
child_database: "하위 데이터베이스",
|
|
5419
|
+
link_preview: "링크 미리보기",
|
|
5420
|
+
breadcrumb: "이동 경로",
|
|
5421
|
+
link_to_page: "페이지 링크",
|
|
5422
|
+
template: "템플릿 버튼",
|
|
5423
|
+
code: "코드 블록"
|
|
5424
|
+
};
|
|
5425
|
+
const ELEMENT_NAME_PREFIXES = [
|
|
5426
|
+
["rich_text:mention:", "멘션"],
|
|
5427
|
+
["rich_text:", "지원하지 않는 서식"],
|
|
5428
|
+
["unsupported:", "지원하지 않는 블록"]
|
|
5429
|
+
];
|
|
5430
|
+
function knownElementName(type) {
|
|
5431
|
+
var _a;
|
|
5432
|
+
if (Object.prototype.hasOwnProperty.call(ELEMENT_NAMES, type)) return ELEMENT_NAMES[type];
|
|
5433
|
+
return (_a = ELEMENT_NAME_PREFIXES.find(([prefix]) => type.startsWith(prefix))) == null ? void 0 : _a[1];
|
|
5434
|
+
}
|
|
5435
|
+
const UNKNOWN_ELEMENT_NAME = "지원하지 않는 블록";
|
|
5436
|
+
function describeUnsupportedElement(type) {
|
|
5437
|
+
return knownElementName(type) ?? UNKNOWN_ELEMENT_NAME;
|
|
5438
|
+
}
|
|
5439
|
+
const ERROR_MESSAGES = {
|
|
5440
|
+
DESCRIPTION_EXTERNAL_CHANGED: "연동된 서비스에서 설명이 먼저 바뀌어 최신 내용을 불러왔습니다. 내용을 확인하고 다시 저장해주세요.",
|
|
5441
|
+
DESCRIPTION_NOT_REPRESENTABLE: "설명에 연동된 서비스가 표현할 수 없는 내용이 있어 저장하지 못했습니다. 해당 내용을 빼고 다시 저장해주세요.",
|
|
5442
|
+
SERVICE_UNAVAILABLE: "연동된 서비스에 연결하지 못했습니다. 잠시 후 다시 시도해주세요."
|
|
5443
|
+
};
|
|
5444
|
+
const SERVICE_NAMES = { JIRA: "Jira", NOTION: "Notion" };
|
|
5445
|
+
function describeSyncService(serviceType) {
|
|
5446
|
+
return SERVICE_NAMES[serviceType];
|
|
5447
|
+
}
|
|
5448
|
+
function describeHiddenKinds(kinds) {
|
|
5449
|
+
return [...new Set(kinds.map(describeUnsupportedElement))].join(", ");
|
|
5450
|
+
}
|
|
5451
|
+
const DESCRIPTION_REFRESH_FAILED_MESSAGE = "설명을 다시 불러오지 못했습니다.";
|
|
5452
|
+
const DESCRIPTION_STRIPPED_SAVE_REJECTED_MESSAGE = "숨긴 내용을 뺀 설명을 저장하지 못했습니다.";
|
|
5453
|
+
function descriptionSyncErrorMessage(code2, serviceType) {
|
|
5454
|
+
if (code2 === "DESCRIPTION_SYNC_LOCKED") {
|
|
5455
|
+
const service = serviceType ? SERVICE_NAMES[serviceType] : "연동된 서비스";
|
|
5456
|
+
return `${service}에서만 고칠 수 있는 부분을 바꿨거나 설명 섹션의 제목이 지워져 저장하지 못했습니다. 바꾼 부분은 원래대로 되돌리고, 지워진 제목은 ${service}에서 되살린 뒤 다시 저장해주세요.`;
|
|
5457
|
+
}
|
|
5458
|
+
return code2 && Object.prototype.hasOwnProperty.call(ERROR_MESSAGES, code2) ? ERROR_MESSAGES[code2] : null;
|
|
5459
|
+
}
|
|
5207
5460
|
function createViewportBounds() {
|
|
5208
5461
|
return {
|
|
5209
5462
|
width: window.innerWidth,
|
|
@@ -5268,16 +5521,19 @@ class WebPlatform {
|
|
|
5268
5521
|
this.screenshot = {
|
|
5269
5522
|
capture: async (options) => {
|
|
5270
5523
|
const excludeSelectors = (options == null ? void 0 : options.excludeSelectors) ?? [];
|
|
5524
|
+
const maskSelectors = (options == null ? void 0 : options.maskSelectors) ?? [];
|
|
5271
5525
|
if (options == null ? void 0 : options.element) {
|
|
5272
|
-
return
|
|
5526
|
+
return captureScreenshotWithMasks({
|
|
5273
5527
|
element: options.element,
|
|
5274
|
-
excludeSelectors
|
|
5528
|
+
excludeSelectors,
|
|
5529
|
+
maskSelectors
|
|
5275
5530
|
});
|
|
5276
5531
|
}
|
|
5277
5532
|
const viewportBounds = createViewportBounds();
|
|
5278
|
-
return
|
|
5533
|
+
return captureScreenshotWithMasks({
|
|
5279
5534
|
element: document.documentElement,
|
|
5280
5535
|
excludeSelectors,
|
|
5536
|
+
maskSelectors,
|
|
5281
5537
|
width: viewportBounds.width,
|
|
5282
5538
|
height: viewportBounds.height
|
|
5283
5539
|
});
|
|
@@ -5826,6 +6082,20 @@ const issueService = {
|
|
|
5826
6082
|
invalidateIssuesCache();
|
|
5827
6083
|
return issue;
|
|
5828
6084
|
},
|
|
6085
|
+
/**
|
|
6086
|
+
* Jira·Notion 의 현재 설명으로 이슈 설명과 숨길 묶음 기록을 다시 만든다.
|
|
6087
|
+
*
|
|
6088
|
+
* 응답(IssueMutationData)에는 연동 매핑이 없어 화면이 숨길 위치를 다시 판단할 수 없다. 호출부가
|
|
6089
|
+
* 이슈를 다시 조회해야 한다. 게스트 소유자 쿼리는 형제 메서드와 같은 규칙이다.
|
|
6090
|
+
*/
|
|
6091
|
+
async refreshIssueDescription(id2) {
|
|
6092
|
+
const issue = await apiClient.post(
|
|
6093
|
+
`${issuesEndpoint()}/${encodeURIComponent(id2)}/description/refresh${guestOwnerQuery()}`,
|
|
6094
|
+
{}
|
|
6095
|
+
);
|
|
6096
|
+
invalidateIssuesCache();
|
|
6097
|
+
return issue;
|
|
6098
|
+
},
|
|
5829
6099
|
/**
|
|
5830
6100
|
* 재생성. 스펙상 세 채널 모두에서 되고 역할과 무관하다 — 검사는 역할이 아니라
|
|
5831
6101
|
* 그 이슈에 접근할 수 있는지다(백엔드가 판정한다).
|
|
@@ -6384,6 +6654,55 @@ const authService = {
|
|
|
6384
6654
|
await apiClient.post("/api/auth/logout", {});
|
|
6385
6655
|
}
|
|
6386
6656
|
};
|
|
6657
|
+
function createWidgetSource() {
|
|
6658
|
+
return createMaskingPolicySource({
|
|
6659
|
+
// 키에 묶인 프로젝트의 유효 정책만 내려온다(계약 1장). issues:create 권한이 없으면 403 으로
|
|
6660
|
+
// 던져져 정책을 쓸 수 없는 상태가 된다. 빈 정책으로 바꾸지 않는다.
|
|
6661
|
+
fetchSnapshot: () => apiClient.get("/api/sdk/masking-policy", { cache: "no-store" }),
|
|
6662
|
+
cache: createMemoryMaskingPolicyCache()
|
|
6663
|
+
});
|
|
6664
|
+
}
|
|
6665
|
+
let current = createWidgetSource();
|
|
6666
|
+
let lastRefreshed = null;
|
|
6667
|
+
let lastRefreshedAt = null;
|
|
6668
|
+
let pending = null;
|
|
6669
|
+
function resetWidgetMaskingPolicy() {
|
|
6670
|
+
current = createWidgetSource();
|
|
6671
|
+
lastRefreshed = null;
|
|
6672
|
+
lastRefreshedAt = null;
|
|
6673
|
+
pending = null;
|
|
6674
|
+
}
|
|
6675
|
+
async function getMaskingPolicySnapshot() {
|
|
6676
|
+
const fresh = lastRefreshed;
|
|
6677
|
+
const stored = await current.getMaskingPolicySnapshot().catch((error) => {
|
|
6678
|
+
if (!fresh) throw error;
|
|
6679
|
+
return null;
|
|
6680
|
+
});
|
|
6681
|
+
return stored && (!fresh || stored.version >= fresh.version) ? stored : fresh;
|
|
6682
|
+
}
|
|
6683
|
+
async function refreshMaskingPolicySnapshot(options) {
|
|
6684
|
+
const source = current;
|
|
6685
|
+
const request2 = source.refreshMaskingPolicySnapshot(options);
|
|
6686
|
+
pending = request2;
|
|
6687
|
+
const snapshot = await request2;
|
|
6688
|
+
if (source === current && (!lastRefreshed || snapshot.version >= lastRefreshed.version)) {
|
|
6689
|
+
lastRefreshed = snapshot;
|
|
6690
|
+
lastRefreshedAt = Date.now();
|
|
6691
|
+
}
|
|
6692
|
+
return snapshot;
|
|
6693
|
+
}
|
|
6694
|
+
function pendingWidgetMaskingPolicyRefresh() {
|
|
6695
|
+
return pending;
|
|
6696
|
+
}
|
|
6697
|
+
function widgetMaskingPolicyRefreshedWithin(maxAgeMs) {
|
|
6698
|
+
if (lastRefreshedAt === null) return false;
|
|
6699
|
+
const age = Date.now() - lastRefreshedAt;
|
|
6700
|
+
return age >= 0 && age <= maxAgeMs;
|
|
6701
|
+
}
|
|
6702
|
+
const widgetMaskingPolicySource = {
|
|
6703
|
+
getMaskingPolicySnapshot,
|
|
6704
|
+
refreshMaskingPolicySnapshot
|
|
6705
|
+
};
|
|
6387
6706
|
const BRIDGE_READY = "ISSUE_STICKER_SDK_AUTH_BRIDGE_READY";
|
|
6388
6707
|
const BRIDGE_REQUEST = "ISSUE_STICKER_SDK_AUTH_REQUEST";
|
|
6389
6708
|
const BRIDGE_RESPONSE = "ISSUE_STICKER_SDK_AUTH_RESPONSE";
|
|
@@ -6527,10 +6846,16 @@ function AuthProvider({ apiKey, children }) {
|
|
|
6527
6846
|
};
|
|
6528
6847
|
await saveToken(result.accessToken);
|
|
6529
6848
|
setSdkMode("member");
|
|
6530
|
-
const
|
|
6531
|
-
const tenantId = ((_a = result.context) == null ? void 0 : _a.tenantId) ||
|
|
6532
|
-
const projectId = ((_b2 = result.context) == null ? void 0 : _b2.projectId) ||
|
|
6533
|
-
const accountId = ((_c2 = result.context) == null ? void 0 : _c2.accountId) ||
|
|
6849
|
+
const current2 = stateRef.current;
|
|
6850
|
+
const tenantId = ((_a = result.context) == null ? void 0 : _a.tenantId) || current2.tenantId;
|
|
6851
|
+
const projectId = ((_b2 = result.context) == null ? void 0 : _b2.projectId) || current2.projectId;
|
|
6852
|
+
const accountId = ((_c2 = result.context) == null ? void 0 : _c2.accountId) || current2.accountId;
|
|
6853
|
+
if (projectId && projectId !== current2.projectId) {
|
|
6854
|
+
resetWidgetMaskingPolicy();
|
|
6855
|
+
void refreshMaskingPolicySnapshot({ timeoutMs: MASKING_POLICY_PREFETCH_TIMEOUT_MS }).catch(
|
|
6856
|
+
() => void 0
|
|
6857
|
+
);
|
|
6858
|
+
}
|
|
6534
6859
|
if (tenantId && projectId) {
|
|
6535
6860
|
await saveAccountInfo({
|
|
6536
6861
|
tenantId,
|
|
@@ -6644,6 +6969,7 @@ function AuthProvider({ apiKey, children }) {
|
|
|
6644
6969
|
const applyPublicContext = useCallback(async () => {
|
|
6645
6970
|
setSdkMode("public");
|
|
6646
6971
|
setApiKey(apiKey);
|
|
6972
|
+
resetWidgetMaskingPolicy();
|
|
6647
6973
|
const result = await authService.publicInit(apiKey);
|
|
6648
6974
|
const user = getConfiguredUser();
|
|
6649
6975
|
const nextAuthBridgeUrl = result.authBridgeUrl ?? null;
|
|
@@ -6667,6 +6993,9 @@ function AuthProvider({ apiKey, children }) {
|
|
|
6667
6993
|
token: null,
|
|
6668
6994
|
error: null
|
|
6669
6995
|
}));
|
|
6996
|
+
void refreshMaskingPolicySnapshot({ timeoutMs: MASKING_POLICY_PREFETCH_TIMEOUT_MS }).catch(
|
|
6997
|
+
() => void 0
|
|
6998
|
+
);
|
|
6670
6999
|
return result;
|
|
6671
7000
|
}, [apiKey, getConfiguredUser]);
|
|
6672
7001
|
useEffect(() => {
|
|
@@ -6703,14 +7032,14 @@ function AuthProvider({ apiKey, children }) {
|
|
|
6703
7032
|
return;
|
|
6704
7033
|
}
|
|
6705
7034
|
if (message.type === BRIDGE_RESPONSE && message.requestId) {
|
|
6706
|
-
const
|
|
6707
|
-
if (!
|
|
6708
|
-
window.clearTimeout(
|
|
7035
|
+
const pending2 = pendingRequestsRef.current.get(message.requestId);
|
|
7036
|
+
if (!pending2) return;
|
|
7037
|
+
window.clearTimeout(pending2.timeoutId);
|
|
6709
7038
|
pendingRequestsRef.current.delete(message.requestId);
|
|
6710
7039
|
if (message.success && message.data) {
|
|
6711
|
-
|
|
7040
|
+
pending2.resolve(message.data);
|
|
6712
7041
|
} else {
|
|
6713
|
-
|
|
7042
|
+
pending2.reject(new Error(((_b2 = message.error) == null ? void 0 : _b2.message) || ((_c2 = message.error) == null ? void 0 : _c2.code) || "Auth failed"));
|
|
6714
7043
|
}
|
|
6715
7044
|
return;
|
|
6716
7045
|
}
|
|
@@ -7873,20 +8202,20 @@ function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce
|
|
|
7873
8202
|
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
7874
8203
|
const sin = Math.sin(angularFreq * t);
|
|
7875
8204
|
const cos = Math.cos(angularFreq * t);
|
|
7876
|
-
const
|
|
8205
|
+
const current3 = target - envelope * (A * sin + initialDelta * cos);
|
|
7877
8206
|
const currentVelocity = /* @__PURE__ */ secondsToMilliseconds(envelope * (sinCoeff * sin + cosCoeff * cos));
|
|
7878
|
-
state.done = Math.abs(currentVelocity) <= restSpeed && Math.abs(target -
|
|
7879
|
-
state.value = state.done ? target :
|
|
8207
|
+
state.done = Math.abs(currentVelocity) <= restSpeed && Math.abs(target - current3) <= restDelta;
|
|
8208
|
+
state.value = state.done ? target : current3;
|
|
7880
8209
|
return state;
|
|
7881
8210
|
}
|
|
7882
|
-
const
|
|
8211
|
+
const current2 = resolveSpring(t);
|
|
7883
8212
|
if (!isResolvedFromDuration) {
|
|
7884
8213
|
const currentVelocity = /* @__PURE__ */ secondsToMilliseconds(resolveVelocity(t));
|
|
7885
|
-
state.done = Math.abs(currentVelocity) <= restSpeed && Math.abs(target -
|
|
8214
|
+
state.done = Math.abs(currentVelocity) <= restSpeed && Math.abs(target - current2) <= restDelta;
|
|
7886
8215
|
} else {
|
|
7887
8216
|
state.done = t >= duration;
|
|
7888
8217
|
}
|
|
7889
|
-
state.value = state.done ? target :
|
|
8218
|
+
state.value = state.done ? target : current2;
|
|
7890
8219
|
return state;
|
|
7891
8220
|
},
|
|
7892
8221
|
toString: () => {
|
|
@@ -7907,9 +8236,9 @@ spring.applyToOptions = (options) => {
|
|
|
7907
8236
|
return options;
|
|
7908
8237
|
};
|
|
7909
8238
|
const velocitySampleDuration = 5;
|
|
7910
|
-
function getGeneratorVelocity(resolveValue, t,
|
|
8239
|
+
function getGeneratorVelocity(resolveValue, t, current2) {
|
|
7911
8240
|
const prevT = Math.max(t - velocitySampleDuration, 0);
|
|
7912
|
-
return /* @__PURE__ */ velocityPerSecond(
|
|
8241
|
+
return /* @__PURE__ */ velocityPerSecond(current2 - resolveValue(prevT), t - prevT);
|
|
7913
8242
|
}
|
|
7914
8243
|
function inertia({ keyframes: keyframes2, velocity = 0, power = 0.8, timeConstant = 325, bounceDamping = 10, bounceStiffness = 500, modifyTarget, min, max, restDelta = 0.5, restSpeed }) {
|
|
7915
8244
|
const origin = keyframes2[0];
|
|
@@ -8286,8 +8615,8 @@ class JSAnimation extends WithPromise {
|
|
|
8286
8615
|
if (this.generator.velocity) {
|
|
8287
8616
|
return this.generator.velocity(t);
|
|
8288
8617
|
}
|
|
8289
|
-
const
|
|
8290
|
-
return getGeneratorVelocity((s) => this.generator.next(s).value, t,
|
|
8618
|
+
const current2 = this.generator.next(t).value;
|
|
8619
|
+
return getGeneratorVelocity((s) => this.generator.next(s).value, t, current2);
|
|
8291
8620
|
}
|
|
8292
8621
|
get speed() {
|
|
8293
8622
|
return this.playbackSpeed;
|
|
@@ -8916,11 +9245,11 @@ class NativeAnimationExtended extends NativeAnimation {
|
|
|
8916
9245
|
});
|
|
8917
9246
|
const sampleTime = Math.max(sampleDelta, time.now() - this.startTime);
|
|
8918
9247
|
const delta = clamp$2(0, sampleDelta, sampleTime - sampleDelta);
|
|
8919
|
-
const
|
|
9248
|
+
const current2 = sampleAnimation.sample(sampleTime).value;
|
|
8920
9249
|
const { name: name2 } = this.options;
|
|
8921
9250
|
if (element2 && name2)
|
|
8922
|
-
setStyle(element2, name2,
|
|
8923
|
-
motionValue2.setWithVelocity(sampleAnimation.sample(Math.max(0, sampleTime - delta)).value,
|
|
9251
|
+
setStyle(element2, name2, current2);
|
|
9252
|
+
motionValue2.setWithVelocity(sampleAnimation.sample(Math.max(0, sampleTime - delta)).value, current2, delta);
|
|
8924
9253
|
sampleAnimation.stop();
|
|
8925
9254
|
}
|
|
8926
9255
|
}
|
|
@@ -8937,11 +9266,11 @@ const isAnimatable = (value, name2) => {
|
|
|
8937
9266
|
return false;
|
|
8938
9267
|
};
|
|
8939
9268
|
function hasKeyframesChanged(keyframes2) {
|
|
8940
|
-
const
|
|
9269
|
+
const current2 = keyframes2[0];
|
|
8941
9270
|
if (keyframes2.length === 1)
|
|
8942
9271
|
return true;
|
|
8943
9272
|
for (let i = 0; i < keyframes2.length; i++) {
|
|
8944
|
-
if (keyframes2[i] !==
|
|
9273
|
+
if (keyframes2[i] !== current2)
|
|
8945
9274
|
return true;
|
|
8946
9275
|
}
|
|
8947
9276
|
}
|
|
@@ -9200,10 +9529,10 @@ class MotionValue {
|
|
|
9200
9529
|
this.setCurrent(init);
|
|
9201
9530
|
this.owner = options.owner;
|
|
9202
9531
|
}
|
|
9203
|
-
setCurrent(
|
|
9204
|
-
this.current =
|
|
9532
|
+
setCurrent(current2) {
|
|
9533
|
+
this.current = current2;
|
|
9205
9534
|
this.updatedAt = time.now();
|
|
9206
|
-
if (this.canTrackVelocity === null &&
|
|
9535
|
+
if (this.canTrackVelocity === null && current2 !== void 0) {
|
|
9207
9536
|
this.canTrackVelocity = isFloat(this.current);
|
|
9208
9537
|
}
|
|
9209
9538
|
}
|
|
@@ -9305,8 +9634,8 @@ class MotionValue {
|
|
|
9305
9634
|
this.passiveEffect(v, this.updateAndNotify);
|
|
9306
9635
|
}
|
|
9307
9636
|
}
|
|
9308
|
-
setWithVelocity(prev,
|
|
9309
|
-
this.set(
|
|
9637
|
+
setWithVelocity(prev, current2, delta) {
|
|
9638
|
+
this.set(current2);
|
|
9310
9639
|
this.prev = void 0;
|
|
9311
9640
|
this.prevFrameValue = prev;
|
|
9312
9641
|
this.prevUpdatedAt = this.updatedAt - delta;
|
|
@@ -9564,17 +9893,17 @@ const splitCSSVariableRegex = (
|
|
|
9564
9893
|
// eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
|
|
9565
9894
|
/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u
|
|
9566
9895
|
);
|
|
9567
|
-
function parseCSSVariable(
|
|
9568
|
-
const match = splitCSSVariableRegex.exec(
|
|
9896
|
+
function parseCSSVariable(current2) {
|
|
9897
|
+
const match = splitCSSVariableRegex.exec(current2);
|
|
9569
9898
|
if (!match)
|
|
9570
9899
|
return [,];
|
|
9571
9900
|
const [, token1, token2, fallback] = match;
|
|
9572
9901
|
return [`--${token1 ?? token2}`, fallback];
|
|
9573
9902
|
}
|
|
9574
9903
|
const maxDepth = 4;
|
|
9575
|
-
function getVariableValue(
|
|
9576
|
-
invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${
|
|
9577
|
-
const [token, fallback] = parseCSSVariable(
|
|
9904
|
+
function getVariableValue(current2, element2, depth = 1) {
|
|
9905
|
+
invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current2}". This may indicate a circular fallback dependency.`, "max-css-var-depth");
|
|
9906
|
+
const [token, fallback] = parseCSSVariable(current2);
|
|
9578
9907
|
if (!token)
|
|
9579
9908
|
return;
|
|
9580
9909
|
const resolved = window.getComputedStyle(element2).getPropertyValue(token);
|
|
@@ -9594,15 +9923,15 @@ function getValueState(visualElement) {
|
|
|
9594
9923
|
}
|
|
9595
9924
|
function resolveVariantFromProps(props, definition2, custom, visualElement) {
|
|
9596
9925
|
if (typeof definition2 === "function") {
|
|
9597
|
-
const [
|
|
9598
|
-
definition2 = definition2(custom !== void 0 ? custom : props.custom,
|
|
9926
|
+
const [current2, velocity] = getValueState(visualElement);
|
|
9927
|
+
definition2 = definition2(custom !== void 0 ? custom : props.custom, current2, velocity);
|
|
9599
9928
|
}
|
|
9600
9929
|
if (typeof definition2 === "string") {
|
|
9601
9930
|
definition2 = props.variants && props.variants[definition2];
|
|
9602
9931
|
}
|
|
9603
9932
|
if (typeof definition2 === "function") {
|
|
9604
|
-
const [
|
|
9605
|
-
definition2 = definition2(custom !== void 0 ? custom : props.custom,
|
|
9933
|
+
const [current2, velocity] = getValueState(visualElement);
|
|
9934
|
+
definition2 = definition2(custom !== void 0 ? custom : props.custom, current2, velocity);
|
|
9606
9935
|
}
|
|
9607
9936
|
return definition2;
|
|
9608
9937
|
}
|
|
@@ -13984,8 +14313,8 @@ const addPointerInfo = (handler) => (event) => isPrimaryPointer(event) && handle
|
|
|
13984
14313
|
function addPointerEvent(target, eventName, handler, options) {
|
|
13985
14314
|
return addDomEvent(target, eventName, addPointerInfo(handler), options);
|
|
13986
14315
|
}
|
|
13987
|
-
const getContextWindow = ({ current }) => {
|
|
13988
|
-
return
|
|
14316
|
+
const getContextWindow = ({ current: current2 }) => {
|
|
14317
|
+
return current2 ? current2.ownerDocument.defaultView : null;
|
|
13989
14318
|
};
|
|
13990
14319
|
const distance = (a, b) => Math.abs(a - b);
|
|
13991
14320
|
function distance2D(a, b) {
|
|
@@ -14075,16 +14404,16 @@ class PanSession {
|
|
|
14075
14404
|
* Start tracking scroll on ancestors and window.
|
|
14076
14405
|
*/
|
|
14077
14406
|
startScrollTracking(element2) {
|
|
14078
|
-
let
|
|
14079
|
-
while (
|
|
14080
|
-
const style = getComputedStyle(
|
|
14407
|
+
let current2 = element2.parentElement;
|
|
14408
|
+
while (current2) {
|
|
14409
|
+
const style = getComputedStyle(current2);
|
|
14081
14410
|
if (overflowStyles.has(style.overflowX) || overflowStyles.has(style.overflowY)) {
|
|
14082
|
-
this.scrollPositions.set(
|
|
14083
|
-
x:
|
|
14084
|
-
y:
|
|
14411
|
+
this.scrollPositions.set(current2, {
|
|
14412
|
+
x: current2.scrollLeft,
|
|
14413
|
+
y: current2.scrollTop
|
|
14085
14414
|
});
|
|
14086
14415
|
}
|
|
14087
|
-
|
|
14416
|
+
current2 = current2.parentElement;
|
|
14088
14417
|
}
|
|
14089
14418
|
this.scrollPositions.set(window, {
|
|
14090
14419
|
x: window.scrollX,
|
|
@@ -14112,11 +14441,11 @@ class PanSession {
|
|
|
14112
14441
|
if (!initial)
|
|
14113
14442
|
return;
|
|
14114
14443
|
const isWindow = target === window;
|
|
14115
|
-
const
|
|
14444
|
+
const current2 = isWindow ? { x: window.scrollX, y: window.scrollY } : {
|
|
14116
14445
|
x: target.scrollLeft,
|
|
14117
14446
|
y: target.scrollTop
|
|
14118
14447
|
};
|
|
14119
|
-
const delta = { x:
|
|
14448
|
+
const delta = { x: current2.x - initial.x, y: current2.y - initial.y };
|
|
14120
14449
|
if (delta.x === 0 && delta.y === 0)
|
|
14121
14450
|
return;
|
|
14122
14451
|
if (isWindow) {
|
|
@@ -14130,7 +14459,7 @@ class PanSession {
|
|
|
14130
14459
|
this.history[0].y -= delta.y;
|
|
14131
14460
|
}
|
|
14132
14461
|
}
|
|
14133
|
-
this.scrollPositions.set(target,
|
|
14462
|
+
this.scrollPositions.set(target, current2);
|
|
14134
14463
|
frame.update(this.updatePoint, true);
|
|
14135
14464
|
}
|
|
14136
14465
|
updateHandlers(handlers2) {
|
|
@@ -14318,18 +14647,18 @@ class VisualElementDragControls {
|
|
|
14318
14647
|
this.visualElement.projection.target = void 0;
|
|
14319
14648
|
}
|
|
14320
14649
|
eachAxis((axis) => {
|
|
14321
|
-
let
|
|
14322
|
-
if (percent.test(
|
|
14650
|
+
let current2 = this.getAxisMotionValue(axis).get() || 0;
|
|
14651
|
+
if (percent.test(current2)) {
|
|
14323
14652
|
const { projection } = this.visualElement;
|
|
14324
14653
|
if (projection && projection.layout) {
|
|
14325
14654
|
const measuredAxis = projection.layout.layoutBox[axis];
|
|
14326
14655
|
if (measuredAxis) {
|
|
14327
14656
|
const length = calcLength(measuredAxis);
|
|
14328
|
-
|
|
14657
|
+
current2 = length * (parseFloat(current2) / 100);
|
|
14329
14658
|
}
|
|
14330
14659
|
}
|
|
14331
14660
|
}
|
|
14332
|
-
this.originPoint[axis] =
|
|
14661
|
+
this.originPoint[axis] = current2;
|
|
14333
14662
|
});
|
|
14334
14663
|
if (onDragStart) {
|
|
14335
14664
|
frame.update(() => onDragStart(event, info), false, true);
|
|
@@ -14547,8 +14876,8 @@ class VisualElementDragControls {
|
|
|
14547
14876
|
const axisValue = this.getAxisMotionValue(axis);
|
|
14548
14877
|
if (projection && projection.layout) {
|
|
14549
14878
|
const { min, max } = projection.layout.layoutBox[axis];
|
|
14550
|
-
const
|
|
14551
|
-
axisValue.set(point2[axis] - mixNumber$1(min, max, 0.5) +
|
|
14879
|
+
const current2 = axisValue.get() || 0;
|
|
14880
|
+
axisValue.set(point2[axis] - mixNumber$1(min, max, 0.5) + current2);
|
|
14552
14881
|
}
|
|
14553
14882
|
});
|
|
14554
14883
|
}
|
|
@@ -14879,10 +15208,10 @@ function handleHoverEvent(node2, event, lifecycle) {
|
|
|
14879
15208
|
}
|
|
14880
15209
|
class HoverGesture extends Feature {
|
|
14881
15210
|
mount() {
|
|
14882
|
-
const { current } = this.node;
|
|
14883
|
-
if (!
|
|
15211
|
+
const { current: current2 } = this.node;
|
|
15212
|
+
if (!current2)
|
|
14884
15213
|
return;
|
|
14885
|
-
this.unmount = hover(
|
|
15214
|
+
this.unmount = hover(current2, (_element, startEvent) => {
|
|
14886
15215
|
handleHoverEvent(this.node, startEvent, "Start");
|
|
14887
15216
|
return (endEvent) => handleHoverEvent(this.node, endEvent, "End");
|
|
14888
15217
|
});
|
|
@@ -14935,11 +15264,11 @@ function handlePressEvent(node2, event, lifecycle) {
|
|
|
14935
15264
|
}
|
|
14936
15265
|
class PressGesture extends Feature {
|
|
14937
15266
|
mount() {
|
|
14938
|
-
const { current } = this.node;
|
|
14939
|
-
if (!
|
|
15267
|
+
const { current: current2 } = this.node;
|
|
15268
|
+
if (!current2)
|
|
14940
15269
|
return;
|
|
14941
15270
|
const { globalTapTarget, propagate } = this.node.props;
|
|
14942
|
-
this.unmount = press(
|
|
15271
|
+
this.unmount = press(current2, (_element, startEvent) => {
|
|
14943
15272
|
handlePressEvent(this.node, startEvent, "Start");
|
|
14944
15273
|
return (endEvent, { success }) => handlePressEvent(this.node, endEvent, success ? "End" : "Cancel");
|
|
14945
15274
|
}, {
|
|
@@ -16646,7 +16975,7 @@ function useJiraConnectNudge(projectId, enabled) {
|
|
|
16646
16975
|
const queryClient2 = useQueryClient();
|
|
16647
16976
|
const isEnabled = enabled && Boolean(projectId);
|
|
16648
16977
|
const {
|
|
16649
|
-
data:
|
|
16978
|
+
data: pending2,
|
|
16650
16979
|
refetch,
|
|
16651
16980
|
isFetched
|
|
16652
16981
|
} = useQuery({
|
|
@@ -16670,7 +16999,7 @@ function useJiraConnectNudge(projectId, enabled) {
|
|
|
16670
16999
|
}
|
|
16671
17000
|
}, [projectId, trackAttempt]);
|
|
16672
17001
|
const needsConnect = Boolean(
|
|
16673
|
-
projectId && (
|
|
17002
|
+
projectId && (pending2 == null ? void 0 : pending2.some((project) => project.projectId === projectId))
|
|
16674
17003
|
);
|
|
16675
17004
|
const isResolving = isEnabled && !isFetched;
|
|
16676
17005
|
return { needsConnect, connect, isResolving };
|
|
@@ -16801,6 +17130,43 @@ function useAuthInfo() {
|
|
|
16801
17130
|
getAuthInfo
|
|
16802
17131
|
};
|
|
16803
17132
|
}
|
|
17133
|
+
async function uploadScreenshot(screenshotDataUrl, issueId, options) {
|
|
17134
|
+
const [firstUrl] = await uploadScreenshots([screenshotDataUrl], issueId, options);
|
|
17135
|
+
if (typeof firstUrl === "string" && firstUrl.length > 0) {
|
|
17136
|
+
return firstUrl;
|
|
17137
|
+
}
|
|
17138
|
+
throw new Error("스크린샷 업로드 응답에 URL이 없습니다.");
|
|
17139
|
+
}
|
|
17140
|
+
async function uploadScreenshots(screenshotDataUrls, issueId, options) {
|
|
17141
|
+
const uploads = await uploadScreenshotDataUrls(
|
|
17142
|
+
screenshotDataUrls,
|
|
17143
|
+
uploadSignedMedia,
|
|
17144
|
+
issueId,
|
|
17145
|
+
options
|
|
17146
|
+
);
|
|
17147
|
+
return uploads.map((upload) => upload == null ? void 0 : upload.url);
|
|
17148
|
+
}
|
|
17149
|
+
function useScreenshotUpload() {
|
|
17150
|
+
const upload = async (screenshotDataUrl, options) => {
|
|
17151
|
+
try {
|
|
17152
|
+
const screenshotUrl = await uploadScreenshot(screenshotDataUrl, void 0, options);
|
|
17153
|
+
return screenshotUrl;
|
|
17154
|
+
} catch {
|
|
17155
|
+
return void 0;
|
|
17156
|
+
}
|
|
17157
|
+
};
|
|
17158
|
+
const uploadMany = async (screenshotDataUrls, options) => {
|
|
17159
|
+
try {
|
|
17160
|
+
return await uploadScreenshots(screenshotDataUrls, void 0, options);
|
|
17161
|
+
} catch {
|
|
17162
|
+
return screenshotDataUrls.map(() => void 0);
|
|
17163
|
+
}
|
|
17164
|
+
};
|
|
17165
|
+
return {
|
|
17166
|
+
upload,
|
|
17167
|
+
uploadMany
|
|
17168
|
+
};
|
|
17169
|
+
}
|
|
16804
17170
|
async function captureScreenshot(options) {
|
|
16805
17171
|
try {
|
|
16806
17172
|
const sdk = SDKManager.getInstance();
|
|
@@ -16808,36 +17174,33 @@ async function captureScreenshot(options) {
|
|
|
16808
17174
|
return await sdk.platform.screenshot.capture(options);
|
|
16809
17175
|
}
|
|
16810
17176
|
} catch (err) {
|
|
17177
|
+
if (err instanceof MaskingCaptureError) throw err;
|
|
16811
17178
|
devLogger.error("screenshotCapture", "스크린샷 캡처 실패:", err);
|
|
16812
17179
|
}
|
|
16813
17180
|
return void 0;
|
|
16814
17181
|
}
|
|
16815
|
-
async function captureViewportAndElement(element2, excludeSelectors) {
|
|
17182
|
+
async function captureViewportAndElement(element2, excludeSelectors, maskSelectors) {
|
|
16816
17183
|
try {
|
|
16817
17184
|
if (SDKManager.getInstance().isInitialized()) {
|
|
16818
|
-
return await
|
|
17185
|
+
return await captureViewportAndElementShots({ element: element2, excludeSelectors, maskSelectors });
|
|
16819
17186
|
}
|
|
16820
17187
|
} catch (err) {
|
|
16821
17188
|
devLogger.error("screenshotCapture", "스크린샷 캡처 실패:", err);
|
|
17189
|
+
if (err instanceof MaskingCaptureError) return { maskingDropped: true };
|
|
16822
17190
|
}
|
|
16823
17191
|
return {};
|
|
16824
17192
|
}
|
|
16825
|
-
function
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
17193
|
+
function resolveCapturedScreenshots(captured) {
|
|
17194
|
+
return {
|
|
17195
|
+
screenshots: captured.screenshots ?? [],
|
|
17196
|
+
maskingDropped: Boolean(captured.maskingDropped),
|
|
17197
|
+
policyKnown: captured.policyKnown !== false
|
|
17198
|
+
};
|
|
16830
17199
|
}
|
|
16831
|
-
async function
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
}
|
|
16836
|
-
if (!position2.screenshotCapture) {
|
|
16837
|
-
return [];
|
|
16838
|
-
}
|
|
16839
|
-
const captured = await position2.screenshotCapture;
|
|
16840
|
-
return toScreenshotList(captured.screenshotDataUrls, captured.screenshotDataUrl);
|
|
17200
|
+
async function resolveClickPositionCapture(position2) {
|
|
17201
|
+
return resolveCapturedScreenshots(
|
|
17202
|
+
position2.screenshots && position2.screenshots.length > 0 || !position2.screenshotCapture ? position2 : await position2.screenshotCapture
|
|
17203
|
+
);
|
|
16841
17204
|
}
|
|
16842
17205
|
const SCREENSHOT_EXCLUDE_SELECTORS = [
|
|
16843
17206
|
'[data-issue-sticker-capture-ignore="true"]',
|
|
@@ -16873,6 +17236,8 @@ function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
|
16873
17236
|
const [clickPosition, setClickPosition] = useState(null);
|
|
16874
17237
|
const clickPositionRef = useRef(null);
|
|
16875
17238
|
const highlightedElementRef = useRef(null);
|
|
17239
|
+
const captureInBackgroundRef = useRef(null);
|
|
17240
|
+
const pendingCaptureRef = useRef(null);
|
|
16876
17241
|
useEffect(() => {
|
|
16877
17242
|
clickPositionRef.current = clickPosition;
|
|
16878
17243
|
}, [clickPosition]);
|
|
@@ -16941,25 +17306,35 @@ function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
|
16941
17306
|
}
|
|
16942
17307
|
}, [recordedVideoFile]);
|
|
16943
17308
|
useEffect(() => {
|
|
16944
|
-
const captureScreenshotsInBackground = async (position2) => {
|
|
17309
|
+
const captureScreenshotsInBackground = async (position2, selectors) => {
|
|
16945
17310
|
await waitForFormOpen();
|
|
16946
|
-
const
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16960
|
-
(
|
|
16961
|
-
|
|
16962
|
-
|
|
17311
|
+
const loaded = selectors ?? await loadCaptureSelectors(() => widgetMaskingPolicySource.getMaskingPolicySnapshot());
|
|
17312
|
+
const maskSelectors = loaded ?? [];
|
|
17313
|
+
const captured = await pauseNetworkLogCollectionWhile(
|
|
17314
|
+
async () => {
|
|
17315
|
+
const viewport = await captureViewportAndElement(
|
|
17316
|
+
position2.element,
|
|
17317
|
+
SCREENSHOT_EXCLUDE_SELECTORS,
|
|
17318
|
+
maskSelectors
|
|
17319
|
+
);
|
|
17320
|
+
let maskingDropped = Boolean(viewport.maskingDropped);
|
|
17321
|
+
const elementShot = viewport.element ?? await captureScreenshot({
|
|
17322
|
+
element: position2.element,
|
|
17323
|
+
excludeSelectors: SCREENSHOT_EXCLUDE_SELECTORS,
|
|
17324
|
+
maskSelectors
|
|
17325
|
+
}).catch((error) => {
|
|
17326
|
+
if (!(error instanceof MaskingCaptureError)) throw error;
|
|
17327
|
+
maskingDropped = true;
|
|
17328
|
+
return void 0;
|
|
17329
|
+
});
|
|
17330
|
+
const screenshots = [viewport.full, elementShot].filter(isCapturedScreenshot);
|
|
17331
|
+
return {
|
|
17332
|
+
screenshots,
|
|
17333
|
+
...maskingDropped ? { maskingDropped } : {},
|
|
17334
|
+
...loaded === null ? { policyKnown: false } : {}
|
|
17335
|
+
};
|
|
17336
|
+
}
|
|
17337
|
+
);
|
|
16963
17338
|
if (clickPositionRef.current === position2) {
|
|
16964
17339
|
const merged = { ...position2, ...captured };
|
|
16965
17340
|
setClickPosition(merged);
|
|
@@ -16967,6 +17342,17 @@ function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
|
16967
17342
|
}
|
|
16968
17343
|
return captured;
|
|
16969
17344
|
};
|
|
17345
|
+
const startCapture = (position2, selectors) => {
|
|
17346
|
+
const tracked = captureScreenshotsInBackground(
|
|
17347
|
+
position2,
|
|
17348
|
+
selectors
|
|
17349
|
+
).finally(() => {
|
|
17350
|
+
if (pendingCaptureRef.current === tracked) pendingCaptureRef.current = null;
|
|
17351
|
+
});
|
|
17352
|
+
pendingCaptureRef.current = tracked;
|
|
17353
|
+
return tracked;
|
|
17354
|
+
};
|
|
17355
|
+
captureInBackgroundRef.current = startCapture;
|
|
16970
17356
|
const handleDocumentClick = (e) => {
|
|
16971
17357
|
if (!isCreatingIssueRef.current) {
|
|
16972
17358
|
return;
|
|
@@ -16997,7 +17383,7 @@ function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
|
16997
17383
|
videoFile: recordedVideoFile ?? void 0
|
|
16998
17384
|
};
|
|
16999
17385
|
if (!newClickPosition.videoFile) {
|
|
17000
|
-
newClickPosition.screenshotCapture =
|
|
17386
|
+
newClickPosition.screenshotCapture = startCapture(newClickPosition);
|
|
17001
17387
|
}
|
|
17002
17388
|
setClickPosition(newClickPosition);
|
|
17003
17389
|
clickPositionRef.current = newClickPosition;
|
|
@@ -17036,49 +17422,96 @@ function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
|
17036
17422
|
setClickPosition(position2);
|
|
17037
17423
|
clickPositionRef.current = position2;
|
|
17038
17424
|
};
|
|
17425
|
+
const recaptureScreenshots = (selectors) => {
|
|
17426
|
+
const pending2 = pendingCaptureRef.current;
|
|
17427
|
+
if (pending2) {
|
|
17428
|
+
return pending2.catch(() => void 0).then(() => recaptureScreenshots(selectors));
|
|
17429
|
+
}
|
|
17430
|
+
const current2 = clickPositionRef.current;
|
|
17431
|
+
const capture = captureInBackgroundRef.current;
|
|
17432
|
+
if (!current2 || current2.videoFile || !capture) return Promise.resolve(null);
|
|
17433
|
+
const next = {
|
|
17434
|
+
...current2,
|
|
17435
|
+
screenshots: void 0,
|
|
17436
|
+
maskingDropped: void 0,
|
|
17437
|
+
policyKnown: void 0
|
|
17438
|
+
};
|
|
17439
|
+
const captured = capture(next, selectors);
|
|
17440
|
+
next.screenshotCapture = captured;
|
|
17441
|
+
setClickPosition(next);
|
|
17442
|
+
clickPositionRef.current = next;
|
|
17443
|
+
return captured;
|
|
17444
|
+
};
|
|
17039
17445
|
return {
|
|
17040
17446
|
clickPosition,
|
|
17041
17447
|
clickPositionRef,
|
|
17042
17448
|
clearClickPosition,
|
|
17043
|
-
setClickPositionManually
|
|
17449
|
+
setClickPositionManually,
|
|
17450
|
+
recaptureScreenshots
|
|
17044
17451
|
};
|
|
17045
17452
|
}
|
|
17046
|
-
async function
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17453
|
+
async function prepareIssueScreenAttachments(input) {
|
|
17454
|
+
var _a, _b2;
|
|
17455
|
+
const { context } = input;
|
|
17456
|
+
const replayController = ((_a = input.sessionReplay) == null ? void 0 : _a.canAttach) ? input.sessionReplay : void 0;
|
|
17457
|
+
let capture = input.includeScreenshots ? await resolveClickPositionCapture(input.position) : null;
|
|
17458
|
+
await (replayController == null ? void 0 : replayController.whenRestarted());
|
|
17459
|
+
const memoSelectors = (replayController == null ? void 0 : replayController.getMaskMemoSelectors()) ?? null;
|
|
17460
|
+
const memoSets = memoSelectors ? [memoSelectors] : [];
|
|
17461
|
+
const assertCovered = (shots = []) => assertScreenRulesCovered(context.rules, [
|
|
17462
|
+
...shots.map((shot) => shot.masks.selectors),
|
|
17463
|
+
...memoSets
|
|
17464
|
+
]);
|
|
17465
|
+
try {
|
|
17466
|
+
assertCovered(capture == null ? void 0 : capture.screenshots);
|
|
17467
|
+
} catch (error) {
|
|
17468
|
+
if (!(error instanceof MaskingScreenRulesChangedError) || (capture == null ? void 0 : capture.policyKnown) !== false || !input.recaptureScreenshots) {
|
|
17469
|
+
throw error;
|
|
17470
|
+
}
|
|
17471
|
+
assertScreenRulesCovered(context.rules, memoSets);
|
|
17472
|
+
const recaptured = await input.recaptureScreenshots(collectSnapshotSelectors(context.snapshot)).catch(() => null);
|
|
17473
|
+
if (!recaptured) throw error;
|
|
17474
|
+
const shotCount = capture.screenshots.length;
|
|
17475
|
+
capture = resolveCapturedScreenshots(recaptured);
|
|
17476
|
+
if (capture.screenshots.length < shotCount) capture.maskingDropped = true;
|
|
17477
|
+
assertCovered(capture.screenshots);
|
|
17478
|
+
}
|
|
17479
|
+
const replay = replayController ? await replayController.takeSnapshot(((_b2 = context.rules) == null ? void 0 : _b2.screen.mask_selectors) ?? []).catch((error) => {
|
|
17480
|
+
if (isMaskingFailure(error)) throw error;
|
|
17481
|
+
devLogger.error(
|
|
17482
|
+
"useIssueSubmission",
|
|
17483
|
+
"세션 리플레이 스냅샷 실패 (이슈 생성 계속):",
|
|
17484
|
+
error
|
|
17485
|
+
);
|
|
17486
|
+
return null;
|
|
17487
|
+
}) : null;
|
|
17488
|
+
let screenshotUrls = [];
|
|
17489
|
+
let screenshotExcluded = null;
|
|
17490
|
+
if (capture) {
|
|
17491
|
+
const maskedDataUrls = await maskScreenshotsForSubmit(capture.screenshots, context.rules);
|
|
17492
|
+
if (maskedDataUrls.length > 0) {
|
|
17493
|
+
const uploaded = await input.uploadScreenshots(maskedDataUrls);
|
|
17494
|
+
screenshotUrls = uploaded.filter(
|
|
17495
|
+
(url) => typeof url === "string" && url.length > 0
|
|
17496
|
+
);
|
|
17497
|
+
}
|
|
17498
|
+
if (capture.maskingDropped) screenshotExcluded = screenshotUrls.length > 0 ? "partial" : "all";
|
|
17050
17499
|
}
|
|
17051
|
-
|
|
17500
|
+
return { screenshotUrls, replay, screenshotExcluded };
|
|
17052
17501
|
}
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
options
|
|
17059
|
-
);
|
|
17060
|
-
return uploads.map((upload) => upload == null ? void 0 : upload.url);
|
|
17502
|
+
function restartReplayStartedWithoutPolicy(context, sessionReplay) {
|
|
17503
|
+
var _a;
|
|
17504
|
+
if ((sessionReplay == null ? void 0 : sessionReplay.canAttach) && ((_a = sessionReplay.getMaskMemoSelectors()) == null ? void 0 : _a.length) === 0 && collectSnapshotSelectors(context.snapshot).length > 0) {
|
|
17505
|
+
void sessionReplay.restartRecording();
|
|
17506
|
+
}
|
|
17061
17507
|
}
|
|
17062
|
-
function
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
}
|
|
17070
|
-
};
|
|
17071
|
-
const uploadMany = async (screenshotDataUrls, options) => {
|
|
17072
|
-
try {
|
|
17073
|
-
return await uploadScreenshots(screenshotDataUrls, void 0, options);
|
|
17074
|
-
} catch {
|
|
17075
|
-
return screenshotDataUrls.map(() => void 0);
|
|
17076
|
-
}
|
|
17077
|
-
};
|
|
17078
|
-
return {
|
|
17079
|
-
upload,
|
|
17080
|
-
uploadMany
|
|
17081
|
-
};
|
|
17508
|
+
function readSocketConnections() {
|
|
17509
|
+
try {
|
|
17510
|
+
return getCollectorSession().socket.getConnections();
|
|
17511
|
+
} catch (error) {
|
|
17512
|
+
devLogger.error("useIssueSubmission", "소켓 연결 수집 실패 (이슈 생성 계속):", error);
|
|
17513
|
+
return [];
|
|
17514
|
+
}
|
|
17082
17515
|
}
|
|
17083
17516
|
function assertSubmittable(data) {
|
|
17084
17517
|
var _a, _b2, _c2;
|
|
@@ -17098,30 +17531,23 @@ function useIssueSubmission({
|
|
|
17098
17531
|
notionIntegrationId,
|
|
17099
17532
|
videoFile,
|
|
17100
17533
|
sessionReplay,
|
|
17101
|
-
snippetId
|
|
17534
|
+
snippetId,
|
|
17535
|
+
onScreenRulesChanged,
|
|
17536
|
+
recaptureScreenshots,
|
|
17537
|
+
videoExclusionNotified
|
|
17102
17538
|
}) {
|
|
17103
17539
|
const failedServicesRef = useRef([]);
|
|
17540
|
+
const maskingOutcomeRef = useRef(NO_MASKING_OUTCOME);
|
|
17104
17541
|
const { fetchNetworkLogs } = useNetworkLogs();
|
|
17105
17542
|
const { fetchConsoleLogs } = useConsoleLogs();
|
|
17106
17543
|
const { getAuthInfo } = useAuthInfo();
|
|
17107
17544
|
const { uploadMany: uploadScreenshots2 } = useScreenshotUpload();
|
|
17108
17545
|
const createIssueMutation = useDebouncedMutation({
|
|
17109
17546
|
mutationFn: async (data) => {
|
|
17110
|
-
var _a
|
|
17547
|
+
var _a;
|
|
17111
17548
|
assertSubmittable(data);
|
|
17112
|
-
let screenshotUrls;
|
|
17113
17549
|
const videoFile2 = data.videoFile ?? data.position.videoFile;
|
|
17114
|
-
|
|
17115
|
-
const screenshotDataUrls = await resolveClickPositionScreenshots(data.position);
|
|
17116
|
-
if (screenshotDataUrls.length > 0) {
|
|
17117
|
-
const uploadedUrls = await uploadScreenshots2(screenshotDataUrls, {
|
|
17118
|
-
useWebWorker: ((_a = SDKManager.getInstance().config.screenshotCompression) == null ? void 0 : _a.useWebWorker) ?? false
|
|
17119
|
-
});
|
|
17120
|
-
screenshotUrls = uploadedUrls.filter(
|
|
17121
|
-
(url) => typeof url === "string" && url.length > 0
|
|
17122
|
-
);
|
|
17123
|
-
}
|
|
17124
|
-
}
|
|
17550
|
+
const authInfo = getAuthInfo();
|
|
17125
17551
|
const allNetworkLogs = await fetchNetworkLogs();
|
|
17126
17552
|
const allConsoleLogs = await fetchConsoleLogs();
|
|
17127
17553
|
const filteredNetworkLogs = filterExcludeServiceRelatedLogs(allNetworkLogs);
|
|
@@ -17129,80 +17555,133 @@ function useIssueSubmission({
|
|
|
17129
17555
|
const limitedNetworkLogs = selectNetworkLogsForSubmit(filteredNetworkLogs);
|
|
17130
17556
|
const networkLogs = compactNetworkLogsForTransport(limitedNetworkLogs) ?? [];
|
|
17131
17557
|
const consoleLogs = filteredConsoleLogs.slice(-CONSOLE_LOG_SUBMIT_LIMIT);
|
|
17558
|
+
const socketConnections = readSocketConnections();
|
|
17132
17559
|
const positionData = data.position.tracked ?? getElementPosition(data.position.element, {
|
|
17133
17560
|
clientX: data.position.x - window.scrollX,
|
|
17134
17561
|
clientY: data.position.y - window.scrollY
|
|
17135
17562
|
});
|
|
17136
|
-
const authInfo = getAuthInfo();
|
|
17137
|
-
const userAgent = navigator.userAgent;
|
|
17138
|
-
const currentUrl = getCurrentPageUrl();
|
|
17139
|
-
const issueData = {
|
|
17140
|
-
url: currentUrl,
|
|
17141
|
-
title: ((_b2 = data.title) == null ? void 0 : _b2.trim()) || void 0,
|
|
17142
|
-
description: ((_c2 = data.description) == null ? void 0 : _c2.trim()) || void 0,
|
|
17143
|
-
intent: ((_d2 = data.intent) == null ? void 0 : _d2.trim()) || void 0,
|
|
17144
|
-
position: {
|
|
17145
|
-
x: data.position.x,
|
|
17146
|
-
y: data.position.y,
|
|
17147
|
-
selector: positionData.selector,
|
|
17148
|
-
xpath: positionData.xpath,
|
|
17149
|
-
viewport: positionData.viewport,
|
|
17150
|
-
elementRect: positionData.elementRect,
|
|
17151
|
-
locator: positionData.locator,
|
|
17152
|
-
component: positionData.component
|
|
17153
|
-
},
|
|
17154
|
-
screenshot: screenshotUrls && screenshotUrls.length > 0 ? screenshotUrls : void 0,
|
|
17155
|
-
...videoFile2 ? { video_pending: true } : {},
|
|
17156
|
-
network_logs: networkLogs,
|
|
17157
|
-
console_logs: consoleLogs.length > 0 ? consoleLogs : void 0,
|
|
17158
|
-
user_agent: userAgent,
|
|
17159
|
-
tenant_id: authInfo.tenantId,
|
|
17160
|
-
project_id: authInfo.projectId,
|
|
17161
|
-
account_id: authInfo.accountId || void 0,
|
|
17162
|
-
snippet_id: snippetId ?? void 0,
|
|
17163
|
-
...buildExternalUserPayload(SDKManager.getInstance().config.user),
|
|
17164
|
-
// 비어 있는 값은 보내지 않는다 — 저장해봐야 값 없음과 같고 요청만 커진다.
|
|
17165
|
-
custom_field_values: Object.entries(customFieldValues ?? {}).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([field_definition_id, value]) => ({ field_definition_id, value }))
|
|
17166
|
-
};
|
|
17167
|
-
if (((_e2 = issueData.custom_field_values) == null ? void 0 : _e2.length) === 0) {
|
|
17168
|
-
delete issueData.custom_field_values;
|
|
17169
|
-
}
|
|
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;
|
|
17181
|
-
}
|
|
17182
|
-
const { networkLogs: fittedNetworkLogs, stillOverBudget } = shrinkNetworkLogsToFit(
|
|
17183
|
-
issueData.network_logs ?? [],
|
|
17184
|
-
measureJsonBytes({ ...issueData, network_logs: void 0 })
|
|
17185
|
-
);
|
|
17186
|
-
issueData.network_logs = fittedNetworkLogs.length > 0 ? fittedNetworkLogs : void 0;
|
|
17187
|
-
if (stillOverBudget) {
|
|
17188
|
-
throw new Error(
|
|
17189
|
-
"이슈 데이터가 전송 한도를 넘어 저장할 수 없습니다. 설명을 줄이거나 첨부를 빼고 다시 시도해주세요."
|
|
17190
|
-
);
|
|
17191
|
-
}
|
|
17192
17563
|
const integrations = buildIssueIntegrationsPayload({
|
|
17193
17564
|
jiraEnabled: jiraService.isConfigured(),
|
|
17194
17565
|
jiraFields: data.jiraFields,
|
|
17195
17566
|
notionEnabled: activeIntegrationType === "NOTION" && Boolean(notionIntegrationId),
|
|
17196
17567
|
notionProperties: data.notionFields
|
|
17197
17568
|
});
|
|
17198
|
-
const createdIssue = await
|
|
17199
|
-
|
|
17569
|
+
const { createdIssue, attachments, excludeVideo, screenshotExcluded } = await runMaskedSubmit(
|
|
17570
|
+
{
|
|
17571
|
+
source: widgetMaskingPolicySource,
|
|
17572
|
+
projectId: authInfo.projectId,
|
|
17573
|
+
prepareScreen: (context) => {
|
|
17574
|
+
var _a2;
|
|
17575
|
+
return prepareIssueScreenAttachments({
|
|
17576
|
+
context,
|
|
17577
|
+
position: data.position,
|
|
17578
|
+
// 정책이 영상을 빼면 이슈에 화면 근거가 남도록 스크린샷을 대신 올린다.
|
|
17579
|
+
includeScreenshots: !videoFile2 || Boolean((_a2 = context.rules) == null ? void 0 : _a2.screen.exclude_video),
|
|
17580
|
+
uploadScreenshots: (dataUrls) => {
|
|
17581
|
+
var _a3;
|
|
17582
|
+
return uploadScreenshots2(dataUrls, {
|
|
17583
|
+
useWebWorker: ((_a3 = SDKManager.getInstance().config.screenshotCompression) == null ? void 0 : _a3.useWebWorker) ?? false
|
|
17584
|
+
});
|
|
17585
|
+
},
|
|
17586
|
+
sessionReplay,
|
|
17587
|
+
recaptureScreenshots
|
|
17588
|
+
});
|
|
17589
|
+
},
|
|
17590
|
+
submit: async (context, screen) => {
|
|
17591
|
+
var _a2, _b2, _c2, _d2, _e2, _f2;
|
|
17592
|
+
const masked = applySubmitMasking({
|
|
17593
|
+
snapshot: context.snapshot,
|
|
17594
|
+
projectId: authInfo.projectId,
|
|
17595
|
+
networkLogs,
|
|
17596
|
+
consoleLogs,
|
|
17597
|
+
socketConnections,
|
|
17598
|
+
pageUrl: getCurrentPageUrl()
|
|
17599
|
+
});
|
|
17600
|
+
const excludeVideo2 = Boolean(videoFile2 && ((_a2 = masked.rules) == null ? void 0 : _a2.screen.exclude_video));
|
|
17601
|
+
const maskSelectors = ((_b2 = context.rules) == null ? void 0 : _b2.screen.mask_selectors) ?? [];
|
|
17602
|
+
const issueData = {
|
|
17603
|
+
url: masked.pageUrl,
|
|
17604
|
+
title: ((_c2 = data.title) == null ? void 0 : _c2.trim()) || void 0,
|
|
17605
|
+
// 마스킹 정책 때문에 버린 스크린샷은 이슈에도 남긴다. 말없이 빼지 않는다.
|
|
17606
|
+
description: screen.screenshotExcluded ? appendMaskingNotice(
|
|
17607
|
+
data.description,
|
|
17608
|
+
screenshotExclusionNotice(screen.screenshotExcluded)
|
|
17609
|
+
) : ((_d2 = data.description) == null ? void 0 : _d2.trim()) || void 0,
|
|
17610
|
+
intent: ((_e2 = data.intent) == null ? void 0 : _e2.trim()) || void 0,
|
|
17611
|
+
position: {
|
|
17612
|
+
x: data.position.x,
|
|
17613
|
+
y: data.position.y,
|
|
17614
|
+
xpath: positionData.xpath,
|
|
17615
|
+
viewport: positionData.viewport,
|
|
17616
|
+
elementRect: positionData.elementRect,
|
|
17617
|
+
// 대상 규칙이 가린 요소의 페이지 텍스트는 selector·위치 지문에도 싣지 않는다.
|
|
17618
|
+
...maskPositionForSubmit(positionData, data.position.element, maskSelectors),
|
|
17619
|
+
component: positionData.component
|
|
17620
|
+
},
|
|
17621
|
+
screenshot: screen.screenshotUrls.length > 0 ? screen.screenshotUrls : void 0,
|
|
17622
|
+
...videoFile2 && !excludeVideo2 ? { video_pending: true } : {},
|
|
17623
|
+
network_logs: masked.networkLogs,
|
|
17624
|
+
console_logs: masked.consoleLogs.length > 0 ? masked.consoleLogs : void 0,
|
|
17625
|
+
user_agent: navigator.userAgent,
|
|
17626
|
+
tenant_id: authInfo.tenantId,
|
|
17627
|
+
project_id: authInfo.projectId,
|
|
17628
|
+
account_id: authInfo.accountId || void 0,
|
|
17629
|
+
snippet_id: snippetId ?? void 0,
|
|
17630
|
+
masking_policy_version: masked.version,
|
|
17631
|
+
...buildExternalUserPayload(SDKManager.getInstance().config.user),
|
|
17632
|
+
// 비어 있는 값은 보내지 않는다 — 저장해봐야 값 없음과 같고 요청만 커진다.
|
|
17633
|
+
custom_field_values: Object.entries(customFieldValues ?? {}).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([field_definition_id, value]) => ({ field_definition_id, value }))
|
|
17634
|
+
};
|
|
17635
|
+
if (((_f2 = issueData.custom_field_values) == null ? void 0 : _f2.length) === 0) {
|
|
17636
|
+
delete issueData.custom_field_values;
|
|
17637
|
+
}
|
|
17638
|
+
const replay = screen.replay;
|
|
17639
|
+
const attachments2 = await collectAttachmentUploads({
|
|
17640
|
+
takeReplay: replay ? async () => replay : void 0,
|
|
17641
|
+
getConnections: () => masked.socketConnections,
|
|
17642
|
+
onError: (kind, error) => devLogger.error(
|
|
17643
|
+
"useIssueSubmission",
|
|
17644
|
+
kind === "replay" ? "세션 리플레이 스냅샷 실패 (이슈 생성 계속):" : "소켓 전사 직렬화 실패 (이슈 생성 계속):",
|
|
17645
|
+
error
|
|
17646
|
+
)
|
|
17647
|
+
});
|
|
17648
|
+
if (hasReplayUpload(attachments2)) {
|
|
17649
|
+
issueData.session_replay_pending = true;
|
|
17650
|
+
}
|
|
17651
|
+
const { networkLogs: fittedNetworkLogs, stillOverBudget } = shrinkNetworkLogsToFit(
|
|
17652
|
+
issueData.network_logs ?? [],
|
|
17653
|
+
measureJsonBytes({ ...issueData, network_logs: void 0 })
|
|
17654
|
+
);
|
|
17655
|
+
issueData.network_logs = fittedNetworkLogs.length > 0 ? fittedNetworkLogs : void 0;
|
|
17656
|
+
if (stillOverBudget) {
|
|
17657
|
+
throw new Error(
|
|
17658
|
+
"이슈 데이터가 전송 한도를 넘어 저장할 수 없습니다. 설명을 줄이거나 첨부를 빼고 다시 시도해주세요."
|
|
17659
|
+
);
|
|
17660
|
+
}
|
|
17661
|
+
const createdIssue2 = await issueService.createIssue({ ...issueData, integrations });
|
|
17662
|
+
restartReplayStartedWithoutPolicy(context, sessionReplay);
|
|
17663
|
+
return {
|
|
17664
|
+
createdIssue: createdIssue2,
|
|
17665
|
+
attachments: attachments2,
|
|
17666
|
+
excludeVideo: excludeVideo2,
|
|
17667
|
+
screenshotExcluded: screen.screenshotExcluded
|
|
17668
|
+
};
|
|
17669
|
+
}
|
|
17670
|
+
}
|
|
17671
|
+
);
|
|
17672
|
+
maskingOutcomeRef.current = {
|
|
17673
|
+
videoExcluded: excludeVideo,
|
|
17674
|
+
videoExclusionNotified: Boolean(videoExclusionNotified),
|
|
17675
|
+
...screenshotExcluded ? { screenshotExcluded } : {}
|
|
17676
|
+
};
|
|
17677
|
+
const uploadVideo = videoFile2 && !excludeVideo ? videoFile2 : null;
|
|
17678
|
+
if (uploadVideo || attachments.length > 0) {
|
|
17200
17679
|
await enqueueIssueUploads({
|
|
17201
17680
|
videoQueue: getWidgetVideoUploadQueue(),
|
|
17202
17681
|
attachmentQueue: getWidgetAttachmentUploadQueue(),
|
|
17203
17682
|
issueId: createdIssue.id,
|
|
17204
17683
|
projectKey: authInfo.projectId,
|
|
17205
|
-
video:
|
|
17684
|
+
video: uploadVideo ? { blob: uploadVideo, mimeType: normalizeUploadMimeType(uploadVideo.type, "video") } : null,
|
|
17206
17685
|
attachments
|
|
17207
17686
|
});
|
|
17208
17687
|
}
|
|
@@ -17210,7 +17689,7 @@ function useIssueSubmission({
|
|
|
17210
17689
|
toast.error(getIntegrationFailureMessage(service));
|
|
17211
17690
|
}
|
|
17212
17691
|
failedServicesRef.current = createdIssue.failed_services ?? [];
|
|
17213
|
-
if (((
|
|
17692
|
+
if (((_a = data.intent) == null ? void 0 : _a.trim()) && createdIssue.generation_status === "skipped") {
|
|
17214
17693
|
toast.warning(ISSUE_DRAFT_DISABLED_MESSAGE);
|
|
17215
17694
|
}
|
|
17216
17695
|
return createdIssue;
|
|
@@ -17219,7 +17698,17 @@ function useIssueSubmission({
|
|
|
17219
17698
|
queryClient.invalidateQueries({ queryKey: ["contentIssues"] });
|
|
17220
17699
|
SDKManager.getInstance().eventBus.emit("issue:created", createdIssue);
|
|
17221
17700
|
},
|
|
17222
|
-
onError: (error) => {
|
|
17701
|
+
onError: (error, data) => {
|
|
17702
|
+
const masking = describeMaskingSubmitFailure(error, {
|
|
17703
|
+
replayRecording: Boolean(sessionReplay == null ? void 0 : sessionReplay.isRecording()),
|
|
17704
|
+
screenshotsRecaptured: !data.position.videoFile
|
|
17705
|
+
});
|
|
17706
|
+
if (masking) {
|
|
17707
|
+
toast.error(masking.message, { title: masking.title, duration: 0 });
|
|
17708
|
+
if (masking.screenRulesChanged) onScreenRulesChanged == null ? void 0 : onScreenRulesChanged();
|
|
17709
|
+
if (masking.restartReplay) void (sessionReplay == null ? void 0 : sessionReplay.restartRecording());
|
|
17710
|
+
return;
|
|
17711
|
+
}
|
|
17223
17712
|
const billing = classifyBillingError(error);
|
|
17224
17713
|
if ((billing == null ? void 0 : billing.kind) === "quota_exceeded") {
|
|
17225
17714
|
toast.error("지금은 이슈를 제출할 수 없습니다. 잠시 후 다시 시도해주세요.");
|
|
@@ -17231,6 +17720,7 @@ function useIssueSubmission({
|
|
|
17231
17720
|
const doSubmit = useCallback(
|
|
17232
17721
|
async ({ title, description, intent }) => {
|
|
17233
17722
|
failedServicesRef.current = [];
|
|
17723
|
+
maskingOutcomeRef.current = NO_MASKING_OUTCOME;
|
|
17234
17724
|
await createIssueMutation.mutateAsync({
|
|
17235
17725
|
title,
|
|
17236
17726
|
description,
|
|
@@ -17240,15 +17730,16 @@ function useIssueSubmission({
|
|
|
17240
17730
|
notionFields,
|
|
17241
17731
|
videoFile
|
|
17242
17732
|
});
|
|
17243
|
-
onSubmit(failedServicesRef.current.length > 0);
|
|
17733
|
+
onSubmit(failedServicesRef.current.length > 0, maskingOutcomeRef.current);
|
|
17244
17734
|
},
|
|
17245
17735
|
[position2, onSubmit, jiraFields, notionFields, videoFile, createIssueMutation]
|
|
17246
17736
|
);
|
|
17247
17737
|
const { execute: submitIssue, isExecuting: isSubmitting } = useGuardedCallback(doSubmit);
|
|
17738
|
+
const submissionError = createIssueMutation.error;
|
|
17248
17739
|
return {
|
|
17249
17740
|
submitIssue,
|
|
17250
17741
|
isSubmitting,
|
|
17251
|
-
error:
|
|
17742
|
+
error: submissionError && !describeMaskingSubmitFailure(submissionError) ? `이슈 생성에 실패했습니다: ${submissionError instanceof Error ? submissionError.message : "알 수 없는 오류"}` : null
|
|
17252
17743
|
};
|
|
17253
17744
|
}
|
|
17254
17745
|
async function fetchSnippets(projectId) {
|
|
@@ -17386,11 +17877,17 @@ function mergeSnippetIntoDescription(currentDescription, prevBody, nextBody) {
|
|
|
17386
17877
|
const base = prevBody ? trimmedCurrent.slice(0, trimmedCurrent.length - prevBody.length).trimEnd() : currentDescription;
|
|
17387
17878
|
return { ref: normalizedNext, description: appendSnippet(base, nextBody) };
|
|
17388
17879
|
}
|
|
17389
|
-
function useSessionReplayController() {
|
|
17880
|
+
function useSessionReplayController(identity = null) {
|
|
17390
17881
|
const controllerRef = useRef(null);
|
|
17391
17882
|
if (!controllerRef.current) {
|
|
17392
17883
|
controllerRef.current = new SessionReplayCaptureController({
|
|
17393
|
-
loadCapabilities: () => apiClient.get("/api/session-replays/capabilities")
|
|
17884
|
+
loadCapabilities: () => apiClient.get("/api/session-replays/capabilities"),
|
|
17885
|
+
// 키에 묶인 프로젝트 정책의 선택자를 메모한다. 위젯은 그 프로젝트로만 제출한다.
|
|
17886
|
+
maskingPolicy: {
|
|
17887
|
+
source: widgetMaskingPolicySource,
|
|
17888
|
+
pendingRefresh: pendingWidgetMaskingPolicyRefresh,
|
|
17889
|
+
refreshedWithin: widgetMaskingPolicyRefreshedWithin
|
|
17890
|
+
}
|
|
17394
17891
|
});
|
|
17395
17892
|
}
|
|
17396
17893
|
const controller = controllerRef.current;
|
|
@@ -17403,15 +17900,30 @@ function useSessionReplayController() {
|
|
|
17403
17900
|
controller.destroy();
|
|
17404
17901
|
};
|
|
17405
17902
|
}, [controller]);
|
|
17406
|
-
const
|
|
17407
|
-
|
|
17408
|
-
|
|
17903
|
+
const startedIdentityRef = useRef(identity);
|
|
17904
|
+
useEffect(() => {
|
|
17905
|
+
if (startedIdentityRef.current === identity) return;
|
|
17906
|
+
startedIdentityRef.current = identity;
|
|
17907
|
+
void controller.restartRecording();
|
|
17908
|
+
}, [controller, identity]);
|
|
17909
|
+
const takeSnapshot = useCallback(
|
|
17910
|
+
async (maskSelectors) => controller.takeSnapshot(maskSelectors),
|
|
17911
|
+
[controller]
|
|
17912
|
+
);
|
|
17913
|
+
const isRecording = useCallback(() => controller.isRecording(), [controller]);
|
|
17914
|
+
const getMaskMemoSelectors = useCallback(() => controller.getMaskMemoSelectors(), [controller]);
|
|
17915
|
+
const whenRestarted = useCallback(() => controller.whenRestarted(), [controller]);
|
|
17916
|
+
const restartRecording = useCallback(() => controller.restartRecording(), [controller]);
|
|
17409
17917
|
const markReportStart = useCallback(() => controller.markReportStart(), [controller]);
|
|
17410
17918
|
const clearReportStart = useCallback(() => controller.clearReportStart(), [controller]);
|
|
17411
17919
|
return {
|
|
17412
17920
|
available: snapshot.available,
|
|
17413
17921
|
canAttach: snapshot.canAttach,
|
|
17922
|
+
isRecording,
|
|
17414
17923
|
takeSnapshot,
|
|
17924
|
+
getMaskMemoSelectors,
|
|
17925
|
+
whenRestarted,
|
|
17926
|
+
restartRecording,
|
|
17415
17927
|
markReportStart,
|
|
17416
17928
|
clearReportStart
|
|
17417
17929
|
};
|
|
@@ -17419,7 +17931,13 @@ function useSessionReplayController() {
|
|
|
17419
17931
|
const DISABLED_CONTROLLER = {
|
|
17420
17932
|
available: false,
|
|
17421
17933
|
canAttach: false,
|
|
17934
|
+
isRecording: () => false,
|
|
17422
17935
|
takeSnapshot: async () => null,
|
|
17936
|
+
getMaskMemoSelectors: () => null,
|
|
17937
|
+
whenRestarted: async () => {
|
|
17938
|
+
},
|
|
17939
|
+
restartRecording: async () => {
|
|
17940
|
+
},
|
|
17423
17941
|
markReportStart: () => {
|
|
17424
17942
|
},
|
|
17425
17943
|
clearReportStart: () => {
|
|
@@ -17427,7 +17945,8 @@ const DISABLED_CONTROLLER = {
|
|
|
17427
17945
|
};
|
|
17428
17946
|
const SessionReplayContext = createContext(null);
|
|
17429
17947
|
function SessionReplayProvider({ children }) {
|
|
17430
|
-
const
|
|
17948
|
+
const { tenantId, projectId } = useAuthContext();
|
|
17949
|
+
const controller = useSessionReplayController(`${tenantId ?? ""}:${projectId ?? ""}`);
|
|
17431
17950
|
return /* @__PURE__ */ jsx(SessionReplayContext.Provider, { value: controller, children });
|
|
17432
17951
|
}
|
|
17433
17952
|
function useSessionReplay() {
|
|
@@ -17682,7 +18201,7 @@ function useCustomFieldValueDraft({
|
|
|
17682
18201
|
}, []);
|
|
17683
18202
|
const setValue = useCallback(
|
|
17684
18203
|
(fieldDefinitionId, value) => {
|
|
17685
|
-
setDraft((
|
|
18204
|
+
setDraft((current2) => ({ ...current2, [fieldDefinitionId]: value }));
|
|
17686
18205
|
clearTimeout(timersRef.current[fieldDefinitionId]);
|
|
17687
18206
|
timersRef.current[fieldDefinitionId] = setTimeout(() => {
|
|
17688
18207
|
delete timersRef.current[fieldDefinitionId];
|
|
@@ -17960,7 +18479,7 @@ function IssueFormJiraFields({
|
|
|
17960
18479
|
const handleIssueTypeChange = (nextIssueTypeId) => {
|
|
17961
18480
|
if (nextIssueTypeId === issueTypeId) return;
|
|
17962
18481
|
onValuesReplace == null ? void 0 : onValuesReplace(
|
|
17963
|
-
(
|
|
18482
|
+
(current2) => switchJiraIssueType(current2, {
|
|
17964
18483
|
exposedFields,
|
|
17965
18484
|
previousFields: fieldDefinitions,
|
|
17966
18485
|
nextFields: pickJiraIssueTypeFields(fields, issueTypes, nextIssueTypeId),
|
|
@@ -18095,12 +18614,35 @@ function SessionReplayLimitNotice({
|
|
|
18095
18614
|
}
|
|
18096
18615
|
return /* @__PURE__ */ jsx("p", { className: "text-xs text-warning", children: "이번 달 리플레이 한도를 모두 사용했습니다. 다음 달에 한도가 초기화되거나, 플랜을 업그레이드하면 다시 첨부할 수 있습니다." });
|
|
18097
18616
|
}
|
|
18617
|
+
function MaskingVideoExcludedNotice({ excluded }) {
|
|
18618
|
+
if (!excluded) {
|
|
18619
|
+
return null;
|
|
18620
|
+
}
|
|
18621
|
+
return /* @__PURE__ */ jsx("p", { className: "text-xs text-warning", children: MASKING_COPY.videoExcluded });
|
|
18622
|
+
}
|
|
18623
|
+
function useMaskingVideoExcluded(source, projectId, hasVideo) {
|
|
18624
|
+
var _a;
|
|
18625
|
+
const { data: snapshot } = useQuery({
|
|
18626
|
+
queryKey: ["maskingPolicySnapshot"],
|
|
18627
|
+
queryFn: () => loadMaskingPolicyForSubmit(source).catch(() => null),
|
|
18628
|
+
enabled: hasVideo,
|
|
18629
|
+
// 워크스페이스를 바꾼 뒤 지난 워크스페이스 스냅샷이나 실패(null)를 신선한 값으로 읽으면 안내가
|
|
18630
|
+
// 틀려 영상이 말없이 빠진다. 앱 전역 QueryClient 의 staleTime·gcTime 과 무관하게 마운트마다 새로 받는다.
|
|
18631
|
+
staleTime: 0,
|
|
18632
|
+
gcTime: 0,
|
|
18633
|
+
refetchOnMount: "always"
|
|
18634
|
+
});
|
|
18635
|
+
if (!hasVideo || !projectId || !snapshot) return false;
|
|
18636
|
+
return ((_a = resolveEffectivePolicy(snapshot, projectId)) == null ? void 0 : _a.screen.exclude_video) ?? false;
|
|
18637
|
+
}
|
|
18098
18638
|
function IssueForm({
|
|
18099
18639
|
position: position2,
|
|
18100
18640
|
onSubmit,
|
|
18101
18641
|
onCancel,
|
|
18102
18642
|
activeIntegration,
|
|
18103
|
-
isIntegrationLoading = false
|
|
18643
|
+
isIntegrationLoading = false,
|
|
18644
|
+
onScreenRulesChanged,
|
|
18645
|
+
recaptureScreenshots
|
|
18104
18646
|
}) {
|
|
18105
18647
|
var _a, _b2;
|
|
18106
18648
|
const { isMember } = useAuthContext();
|
|
@@ -18161,18 +18703,33 @@ function IssueForm({
|
|
|
18161
18703
|
const integrationFieldSkeletonCount = Math.max(jiraService.getExposedFields().length, 2);
|
|
18162
18704
|
const submitSucceededRef = useRef(false);
|
|
18163
18705
|
const hadIntegrationFailureRef = useRef(false);
|
|
18706
|
+
const maskingOutcomeRef = useRef(NO_MASKING_OUTCOME);
|
|
18707
|
+
const videoExcludedByPolicy = useMaskingVideoExcluded(
|
|
18708
|
+
widgetMaskingPolicySource,
|
|
18709
|
+
selectedProjectId ?? null,
|
|
18710
|
+
Boolean(position2.videoFile)
|
|
18711
|
+
);
|
|
18712
|
+
const handleScreenRulesChanged = () => {
|
|
18713
|
+
onScreenRulesChanged == null ? void 0 : onScreenRulesChanged();
|
|
18714
|
+
void sessionReplay.restartRecording();
|
|
18715
|
+
};
|
|
18164
18716
|
const issueSubmission = useIssueSubmission({
|
|
18165
18717
|
position: position2,
|
|
18166
|
-
|
|
18718
|
+
onScreenRulesChanged: handleScreenRulesChanged,
|
|
18719
|
+
recaptureScreenshots,
|
|
18720
|
+
onSubmit: (hasIntegrationFailure, outcome) => {
|
|
18167
18721
|
void snippets.rememberSelection();
|
|
18168
18722
|
if (formState.mode === "ai") {
|
|
18169
|
-
onSubmit(hasIntegrationFailure);
|
|
18723
|
+
onSubmit(hasIntegrationFailure, outcome);
|
|
18170
18724
|
return;
|
|
18171
18725
|
}
|
|
18172
18726
|
submitSucceededRef.current = true;
|
|
18173
18727
|
hadIntegrationFailureRef.current = hasIntegrationFailure;
|
|
18728
|
+
maskingOutcomeRef.current = outcome;
|
|
18174
18729
|
setIsOpen(false);
|
|
18175
18730
|
},
|
|
18731
|
+
// 녹화 제외 안내는 직접 작성 폼에만 있다. AI 작성 말풍선으로 냈으면 완료 토스트가 알린다.
|
|
18732
|
+
videoExclusionNotified: formState.mode === "manual" && videoExcludedByPolicy,
|
|
18176
18733
|
jiraFields,
|
|
18177
18734
|
notionFields,
|
|
18178
18735
|
customFieldValues,
|
|
@@ -18251,14 +18808,14 @@ function IssueForm({
|
|
|
18251
18808
|
IssueFormJiraFieldDefaults,
|
|
18252
18809
|
{
|
|
18253
18810
|
integrationId: jiraIntegrationId,
|
|
18254
|
-
onDefaultsResolved: (defaults) => setJiraFields((
|
|
18811
|
+
onDefaultsResolved: (defaults) => setJiraFields((current2) => ({ ...defaults, ...current2 }))
|
|
18255
18812
|
}
|
|
18256
18813
|
) }) : null,
|
|
18257
18814
|
showCustomFields ? /* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: null, onError: () => null, children: /* @__PURE__ */ jsx(
|
|
18258
18815
|
IssueFormCustomFieldDefaults,
|
|
18259
18816
|
{
|
|
18260
18817
|
projectId: selectedProjectId,
|
|
18261
|
-
onDefaultsResolved: (defaults) => setCustomFieldValues((
|
|
18818
|
+
onDefaultsResolved: (defaults) => setCustomFieldValues((current2) => ({ ...defaults, ...current2 }))
|
|
18262
18819
|
}
|
|
18263
18820
|
) }) : null,
|
|
18264
18821
|
/* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: null, onError: () => null, children: /* @__PURE__ */ jsx(IssueFormDraftCapabilityGate, { onResolved: handleDraftCapabilityResolved }) }),
|
|
@@ -18302,7 +18859,7 @@ function IssueForm({
|
|
|
18302
18859
|
return;
|
|
18303
18860
|
}
|
|
18304
18861
|
if (submitSucceededRef.current) {
|
|
18305
|
-
onSubmit(hadIntegrationFailureRef.current);
|
|
18862
|
+
onSubmit(hadIntegrationFailureRef.current, maskingOutcomeRef.current);
|
|
18306
18863
|
} else {
|
|
18307
18864
|
onCancel();
|
|
18308
18865
|
}
|
|
@@ -18331,6 +18888,7 @@ function IssueForm({
|
|
|
18331
18888
|
canAttach: sessionReplay.canAttach
|
|
18332
18889
|
}
|
|
18333
18890
|
) : null,
|
|
18891
|
+
/* @__PURE__ */ jsx(MaskingVideoExcludedNotice, { excluded: videoExcludedByPolicy }),
|
|
18334
18892
|
/* @__PURE__ */ jsx(
|
|
18335
18893
|
IssueFormTitleField,
|
|
18336
18894
|
{
|
|
@@ -18360,12 +18918,12 @@ function IssueForm({
|
|
|
18360
18918
|
values: jiraFields,
|
|
18361
18919
|
disabled: issueSubmission.isSubmitting,
|
|
18362
18920
|
onChange: (fieldId, value) => {
|
|
18363
|
-
setJiraFields((
|
|
18364
|
-
...
|
|
18921
|
+
setJiraFields((current2) => ({
|
|
18922
|
+
...current2,
|
|
18365
18923
|
[fieldId]: value
|
|
18366
18924
|
}));
|
|
18367
18925
|
},
|
|
18368
|
-
onDefaultsResolved: (defaults) => setJiraFields((
|
|
18926
|
+
onDefaultsResolved: (defaults) => setJiraFields((current2) => ({ ...defaults, ...current2 })),
|
|
18369
18927
|
onValuesReplace: setJiraFields
|
|
18370
18928
|
}
|
|
18371
18929
|
)
|
|
@@ -18389,8 +18947,8 @@ function IssueForm({
|
|
|
18389
18947
|
values: notionFields,
|
|
18390
18948
|
disabled: issueSubmission.isSubmitting,
|
|
18391
18949
|
onChange: (fieldId, value) => {
|
|
18392
|
-
setNotionFields((
|
|
18393
|
-
...
|
|
18950
|
+
setNotionFields((current2) => ({
|
|
18951
|
+
...current2,
|
|
18394
18952
|
[fieldId]: value
|
|
18395
18953
|
}));
|
|
18396
18954
|
}
|
|
@@ -18404,8 +18962,8 @@ function IssueForm({
|
|
|
18404
18962
|
projectId: selectedProjectId,
|
|
18405
18963
|
values: customFieldValues,
|
|
18406
18964
|
disabled: issueSubmission.isSubmitting,
|
|
18407
|
-
onChange: (fieldId, value) => setCustomFieldValues((
|
|
18408
|
-
onDefaultsResolved: (defaults) => setCustomFieldValues((
|
|
18965
|
+
onChange: (fieldId, value) => setCustomFieldValues((current2) => ({ ...current2, [fieldId]: value })),
|
|
18966
|
+
onDefaultsResolved: (defaults) => setCustomFieldValues((current2) => ({ ...defaults, ...current2 }))
|
|
18409
18967
|
}
|
|
18410
18968
|
) }) : null
|
|
18411
18969
|
] }),
|
|
@@ -18418,6 +18976,18 @@ function IssueForm({
|
|
|
18418
18976
|
getPortalContainer()
|
|
18419
18977
|
);
|
|
18420
18978
|
}
|
|
18979
|
+
function descriptionExternalUrl(issue, serviceType, jiraSiteUrl) {
|
|
18980
|
+
var _a, _b2;
|
|
18981
|
+
if (serviceType === "NOTION") {
|
|
18982
|
+
return ((_a = getNotionPageMetadata(getPrimaryNotionMapping(issue))) == null ? void 0 : _a.notion_page_url) ?? null;
|
|
18983
|
+
}
|
|
18984
|
+
if (serviceType === "JIRA") {
|
|
18985
|
+
const key = (_b2 = getJiraMetadata(getPrimaryJiraMapping(issue))) == null ? void 0 : _b2.jira_key;
|
|
18986
|
+
const site = jiraSiteUrl == null ? void 0 : jiraSiteUrl.replace(/\/+$/, "");
|
|
18987
|
+
return key && site ? `${site}/browse/${key}` : null;
|
|
18988
|
+
}
|
|
18989
|
+
return null;
|
|
18990
|
+
}
|
|
18421
18991
|
function useJiraIssueSync(issue) {
|
|
18422
18992
|
const [isSyncingAll, setIsSyncingAll] = useState(false);
|
|
18423
18993
|
const mapping = getPrimaryJiraMapping(issue);
|
|
@@ -18451,6 +19021,39 @@ function useJiraIssueSync(issue) {
|
|
|
18451
19021
|
canSync
|
|
18452
19022
|
};
|
|
18453
19023
|
}
|
|
19024
|
+
const REFETCH_STATUSES = /* @__PURE__ */ new Set([400, 404, 409]);
|
|
19025
|
+
function useRefreshIssueDescription(issueId, issueQueryKey, onUpdated) {
|
|
19026
|
+
const queryClient2 = useQueryClient();
|
|
19027
|
+
const reload = useCallback(async () => {
|
|
19028
|
+
await queryClient2.cancelQueries({ queryKey: issueQueryKey, exact: true });
|
|
19029
|
+
return queryClient2.fetchQuery({
|
|
19030
|
+
queryKey: issueQueryKey,
|
|
19031
|
+
queryFn: () => issueService.getIssue(issueId),
|
|
19032
|
+
staleTime: 0
|
|
19033
|
+
});
|
|
19034
|
+
}, [issueId, issueQueryKey, queryClient2]);
|
|
19035
|
+
const refresh = useCallback(async () => {
|
|
19036
|
+
try {
|
|
19037
|
+
await issueService.refreshIssueDescription(issueId);
|
|
19038
|
+
} catch (error) {
|
|
19039
|
+
const status = error == null ? void 0 : error.status;
|
|
19040
|
+
if (status !== void 0 && REFETCH_STATUSES.has(status)) invalidateIssueQueries(issueId);
|
|
19041
|
+
throw error;
|
|
19042
|
+
}
|
|
19043
|
+
let fresh;
|
|
19044
|
+
try {
|
|
19045
|
+
fresh = await reload();
|
|
19046
|
+
} catch (error) {
|
|
19047
|
+
invalidateIssueQueries(issueId);
|
|
19048
|
+
throw error;
|
|
19049
|
+
}
|
|
19050
|
+
queryClient2.invalidateQueries({ queryKey: ["contentIssues"] });
|
|
19051
|
+
notifyIssueUpdated(issueId);
|
|
19052
|
+
onUpdated == null ? void 0 : onUpdated();
|
|
19053
|
+
return fresh;
|
|
19054
|
+
}, [issueId, onUpdated, queryClient2, reload]);
|
|
19055
|
+
return { refresh, reload };
|
|
19056
|
+
}
|
|
18454
19057
|
const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false, "VITE_ADMIN_BASE_URL": "https://app.issuesticker.com", "VITE_API_BASE_URL": "https://api.issuesticker.com" };
|
|
18455
19058
|
function readViteEnv(name2) {
|
|
18456
19059
|
var _a;
|
|
@@ -20220,6 +20823,132 @@ function ConsoleLogsSection({
|
|
|
20220
20823
|
function IssueCreatedAt({ createdAt }) {
|
|
20221
20824
|
return /* @__PURE__ */ jsx("div", { className: "text-right text-xs text-text-tertiary", children: new Date(createdAt).toLocaleString("ko-KR") });
|
|
20222
20825
|
}
|
|
20826
|
+
function safeHttpUrl(value) {
|
|
20827
|
+
if (!value) return null;
|
|
20828
|
+
try {
|
|
20829
|
+
const { protocol } = new URL(value);
|
|
20830
|
+
return protocol === "https:" || protocol === "http:" ? value : null;
|
|
20831
|
+
} catch {
|
|
20832
|
+
return null;
|
|
20833
|
+
}
|
|
20834
|
+
}
|
|
20835
|
+
function mergeByLabel(elements) {
|
|
20836
|
+
const counts = /* @__PURE__ */ new Map();
|
|
20837
|
+
for (const { type, count } of elements) {
|
|
20838
|
+
const label = describeUnsupportedElement(type);
|
|
20839
|
+
counts.set(label, (counts.get(label) ?? 0) + count);
|
|
20840
|
+
}
|
|
20841
|
+
return [...counts];
|
|
20842
|
+
}
|
|
20843
|
+
function DescriptionSyncLockNotice({
|
|
20844
|
+
lock,
|
|
20845
|
+
externalUrl,
|
|
20846
|
+
canEdit = true
|
|
20847
|
+
}) {
|
|
20848
|
+
const service = describeSyncService(lock.serviceType);
|
|
20849
|
+
const href = safeHttpUrl(externalUrl);
|
|
20850
|
+
const Icon2 = lock.blocksEditing ? Lock : Info$1;
|
|
20851
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-line-subtle py-3 text-sm", children: [
|
|
20852
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-text-primary", children: [
|
|
20853
|
+
/* @__PURE__ */ jsx(Icon2, { className: "mt-0.5 size-4 shrink-0 text-text-tertiary", "aria-hidden": true }),
|
|
20854
|
+
lock.blocksEditing ? /* @__PURE__ */ jsxs("p", { children: [
|
|
20855
|
+
service,
|
|
20856
|
+
"에서 설명 섹션의 제목이 지워져 설명을 동기화할 수 없습니다. ",
|
|
20857
|
+
service,
|
|
20858
|
+
"에서 지운 제목을 되살리면 다시 수정할 수 있습니다."
|
|
20859
|
+
] }) : /* @__PURE__ */ jsxs("p", { children: [
|
|
20860
|
+
"이 설명에는 ",
|
|
20861
|
+
service,
|
|
20862
|
+
"에서만 고칠 수 있는 요소가 있습니다.",
|
|
20863
|
+
canEdit ? " 나머지 설명은 이곳에서 수정할 수 있습니다." : null
|
|
20864
|
+
] })
|
|
20865
|
+
] }),
|
|
20866
|
+
/* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-x-3 gap-y-1 pl-6 text-xs text-text-secondary", children: mergeByLabel(lock.elements).map(([label, count]) => /* @__PURE__ */ jsxs("li", { children: [
|
|
20867
|
+
label,
|
|
20868
|
+
" ",
|
|
20869
|
+
count,
|
|
20870
|
+
"개"
|
|
20871
|
+
] }, label)) }),
|
|
20872
|
+
href ? /* @__PURE__ */ jsxs(
|
|
20873
|
+
"a",
|
|
20874
|
+
{
|
|
20875
|
+
href,
|
|
20876
|
+
target: "_blank",
|
|
20877
|
+
rel: "noopener noreferrer",
|
|
20878
|
+
className: "flex items-center gap-1 self-start pl-6 text-xs text-text-secondary underline-offset-2 hover:underline",
|
|
20879
|
+
children: [
|
|
20880
|
+
service,
|
|
20881
|
+
"에서 열기",
|
|
20882
|
+
/* @__PURE__ */ jsx(ExternalLink$1, { className: "size-3", "aria-hidden": true })
|
|
20883
|
+
]
|
|
20884
|
+
}
|
|
20885
|
+
) : null
|
|
20886
|
+
] });
|
|
20887
|
+
}
|
|
20888
|
+
function HiddenDescriptionNotice({
|
|
20889
|
+
serviceType,
|
|
20890
|
+
kinds,
|
|
20891
|
+
externalUrl
|
|
20892
|
+
}) {
|
|
20893
|
+
const service = describeSyncService(serviceType);
|
|
20894
|
+
const href = safeHttpUrl(externalUrl);
|
|
20895
|
+
const names = describeHiddenKinds(kinds);
|
|
20896
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-line-subtle py-3 text-sm", children: [
|
|
20897
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-text-primary", children: [
|
|
20898
|
+
/* @__PURE__ */ jsx(Info$1, { className: "mt-0.5 size-4 shrink-0 text-text-tertiary", "aria-hidden": true }),
|
|
20899
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
20900
|
+
service,
|
|
20901
|
+
"에서만 수정할 수 있는 내용",
|
|
20902
|
+
names ? `(${names})` : "",
|
|
20903
|
+
"은 편집에서 숨겼습니다. 저장해도 ",
|
|
20904
|
+
service,
|
|
20905
|
+
"에는 그대로 남습니다."
|
|
20906
|
+
] })
|
|
20907
|
+
] }),
|
|
20908
|
+
href ? /* @__PURE__ */ jsxs(
|
|
20909
|
+
"a",
|
|
20910
|
+
{
|
|
20911
|
+
href,
|
|
20912
|
+
target: "_blank",
|
|
20913
|
+
rel: "noopener noreferrer",
|
|
20914
|
+
className: "flex items-center gap-1 self-start pl-6 text-xs text-text-secondary underline-offset-2 hover:underline",
|
|
20915
|
+
children: [
|
|
20916
|
+
service,
|
|
20917
|
+
"에서 열기",
|
|
20918
|
+
/* @__PURE__ */ jsx(ExternalLink$1, { className: "size-3", "aria-hidden": true })
|
|
20919
|
+
]
|
|
20920
|
+
}
|
|
20921
|
+
) : null
|
|
20922
|
+
] });
|
|
20923
|
+
}
|
|
20924
|
+
function DescriptionRefreshNotice({
|
|
20925
|
+
onRefresh,
|
|
20926
|
+
isRefreshing
|
|
20927
|
+
}) {
|
|
20928
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-line-subtle py-3 text-sm", children: [
|
|
20929
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-text-primary", children: [
|
|
20930
|
+
/* @__PURE__ */ jsx(Info$1, { className: "mt-0.5 size-4 shrink-0 text-text-tertiary", "aria-hidden": true }),
|
|
20931
|
+
/* @__PURE__ */ jsx("p", { children: "설명을 다시 불러와야 수정할 수 있습니다." })
|
|
20932
|
+
] }),
|
|
20933
|
+
/* @__PURE__ */ jsx(
|
|
20934
|
+
Button,
|
|
20935
|
+
{
|
|
20936
|
+
type: "button",
|
|
20937
|
+
variant: "secondary",
|
|
20938
|
+
size: "sm",
|
|
20939
|
+
onClick: onRefresh,
|
|
20940
|
+
disabled: isRefreshing,
|
|
20941
|
+
className: "self-start",
|
|
20942
|
+
children: isRefreshing ? "다시 불러오는 중..." : "다시 불러오기"
|
|
20943
|
+
}
|
|
20944
|
+
)
|
|
20945
|
+
] });
|
|
20946
|
+
}
|
|
20947
|
+
function DescriptionEditBasisChangedNotice({
|
|
20948
|
+
reason = "changed"
|
|
20949
|
+
}) {
|
|
20950
|
+
return /* @__PURE__ */ jsx("p", { role: "status", className: "py-2 text-sm text-text-primary", children: reason === "rejected" ? "이 설명은 숨긴 내용을 함께 표시한 상태에서만 저장할 수 있습니다. 입력한 내용을 복사한 뒤 「취소」를 클릭하고 다시 수정해주세요." : "설명이 바뀌어 지금 입력한 내용은 저장할 수 없습니다. 입력한 내용을 복사한 뒤 「취소」를 클릭하고 다시 수정해주세요." });
|
|
20951
|
+
}
|
|
20223
20952
|
function ok$1() {
|
|
20224
20953
|
}
|
|
20225
20954
|
function unreachable() {
|
|
@@ -25891,34 +26620,34 @@ function subcontent(events, eventIndex) {
|
|
|
25891
26620
|
let stream;
|
|
25892
26621
|
let previous2;
|
|
25893
26622
|
let index2 = -1;
|
|
25894
|
-
let
|
|
26623
|
+
let current2 = token;
|
|
25895
26624
|
let adjust = 0;
|
|
25896
26625
|
let start = 0;
|
|
25897
26626
|
const breaks = [start];
|
|
25898
|
-
while (
|
|
25899
|
-
while (events.get(++startPosition)[1] !==
|
|
26627
|
+
while (current2) {
|
|
26628
|
+
while (events.get(++startPosition)[1] !== current2) {
|
|
25900
26629
|
}
|
|
25901
26630
|
startPositions.push(startPosition);
|
|
25902
|
-
if (!
|
|
25903
|
-
stream = context.sliceStream(
|
|
25904
|
-
if (!
|
|
26631
|
+
if (!current2._tokenizer) {
|
|
26632
|
+
stream = context.sliceStream(current2);
|
|
26633
|
+
if (!current2.next) {
|
|
25905
26634
|
stream.push(null);
|
|
25906
26635
|
}
|
|
25907
26636
|
if (previous2) {
|
|
25908
|
-
tokenizer.defineSkip(
|
|
26637
|
+
tokenizer.defineSkip(current2.start);
|
|
25909
26638
|
}
|
|
25910
|
-
if (
|
|
26639
|
+
if (current2._isInFirstContentOfListItem) {
|
|
25911
26640
|
tokenizer._gfmTasklistFirstContentOfListItem = true;
|
|
25912
26641
|
}
|
|
25913
26642
|
tokenizer.write(stream);
|
|
25914
|
-
if (
|
|
26643
|
+
if (current2._isInFirstContentOfListItem) {
|
|
25915
26644
|
tokenizer._gfmTasklistFirstContentOfListItem = void 0;
|
|
25916
26645
|
}
|
|
25917
26646
|
}
|
|
25918
|
-
previous2 =
|
|
25919
|
-
|
|
26647
|
+
previous2 = current2;
|
|
26648
|
+
current2 = current2.next;
|
|
25920
26649
|
}
|
|
25921
|
-
|
|
26650
|
+
current2 = token;
|
|
25922
26651
|
while (++index2 < childEvents.length) {
|
|
25923
26652
|
if (
|
|
25924
26653
|
// Find a void token that includes a break.
|
|
@@ -25926,15 +26655,15 @@ function subcontent(events, eventIndex) {
|
|
|
25926
26655
|
) {
|
|
25927
26656
|
start = index2 + 1;
|
|
25928
26657
|
breaks.push(start);
|
|
25929
|
-
|
|
25930
|
-
|
|
25931
|
-
|
|
26658
|
+
current2._tokenizer = void 0;
|
|
26659
|
+
current2.previous = void 0;
|
|
26660
|
+
current2 = current2.next;
|
|
25932
26661
|
}
|
|
25933
26662
|
}
|
|
25934
26663
|
tokenizer.events = [];
|
|
25935
|
-
if (
|
|
25936
|
-
|
|
25937
|
-
|
|
26664
|
+
if (current2) {
|
|
26665
|
+
current2._tokenizer = void 0;
|
|
26666
|
+
current2.previous = void 0;
|
|
25938
26667
|
} else {
|
|
25939
26668
|
breaks.pop();
|
|
25940
26669
|
}
|
|
@@ -31898,7 +32627,7 @@ const deprecations = [
|
|
|
31898
32627
|
{ from: "transformImageUri", id: "#add-urltransform", to: "urlTransform" },
|
|
31899
32628
|
{ from: "transformLinkUri", id: "#add-urltransform", to: "urlTransform" }
|
|
31900
32629
|
];
|
|
31901
|
-
function Markdown(options) {
|
|
32630
|
+
function Markdown$1(options) {
|
|
31902
32631
|
const processor = createProcessor(options);
|
|
31903
32632
|
const file = createFile(options);
|
|
31904
32633
|
return post(processor.runSync(processor.parse(file), file), options);
|
|
@@ -31995,33 +32724,6 @@ function defaultUrlTransform(value) {
|
|
|
31995
32724
|
}
|
|
31996
32725
|
return "";
|
|
31997
32726
|
}
|
|
31998
|
-
function useIssueFieldUpdate(issueId, onUpdated) {
|
|
31999
|
-
const [error, setError] = useState(null);
|
|
32000
|
-
const [savingField, setSavingField] = useState(null);
|
|
32001
|
-
const updateField = useCallback(
|
|
32002
|
-
async (field, value) => {
|
|
32003
|
-
setError(null);
|
|
32004
|
-
setSavingField(field);
|
|
32005
|
-
try {
|
|
32006
|
-
await issueService.updateIssue(issueId, { [field]: value });
|
|
32007
|
-
applyIssueMutationEffects(issueId);
|
|
32008
|
-
onUpdated == null ? void 0 : onUpdated();
|
|
32009
|
-
return true;
|
|
32010
|
-
} catch (err) {
|
|
32011
|
-
setError(err instanceof Error ? err.message : "이슈 업데이트에 실패했습니다.");
|
|
32012
|
-
return false;
|
|
32013
|
-
} finally {
|
|
32014
|
-
setSavingField((current) => current === field ? null : current);
|
|
32015
|
-
}
|
|
32016
|
-
},
|
|
32017
|
-
[issueId, onUpdated]
|
|
32018
|
-
);
|
|
32019
|
-
return {
|
|
32020
|
-
error,
|
|
32021
|
-
savingField,
|
|
32022
|
-
updateField
|
|
32023
|
-
};
|
|
32024
|
-
}
|
|
32025
32727
|
function ccount(value, character) {
|
|
32026
32728
|
const source = String(value);
|
|
32027
32729
|
if (typeof character !== "string") {
|
|
@@ -35121,29 +35823,300 @@ const markdownComponents = {
|
|
|
35121
35823
|
th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-semibold text-text-primary", children }),
|
|
35122
35824
|
td: ({ children }) => /* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-text-primary", children })
|
|
35123
35825
|
};
|
|
35826
|
+
function Markdown({ children }) {
|
|
35827
|
+
return /* @__PURE__ */ jsx(Markdown$1, { remarkPlugins: markdownRemarkPlugins, components: markdownComponents, children });
|
|
35828
|
+
}
|
|
35829
|
+
const HANGUL_START = 44032;
|
|
35830
|
+
function topicParticle(text2) {
|
|
35831
|
+
return (text2.charCodeAt(text2.length - 1) - HANGUL_START) % 28 === 0 ? "는" : "은";
|
|
35832
|
+
}
|
|
35833
|
+
const READ_ONLY_CLASS = "my-2 border-l-2 border-line pl-3 [&_:is(h1,h2,h3,h4,h5,h6,p,li,td,th,summary,blockquote)]:text-text-secondary";
|
|
35834
|
+
function IssueDescriptionView({
|
|
35835
|
+
description,
|
|
35836
|
+
view
|
|
35837
|
+
}) {
|
|
35838
|
+
const pieces = view == null ? void 0 : view.pieces;
|
|
35839
|
+
if (!view || !(pieces == null ? void 0 : pieces.some((piece) => piece.kind === "hidden"))) {
|
|
35840
|
+
return /* @__PURE__ */ jsx(Markdown, { children: description });
|
|
35841
|
+
}
|
|
35842
|
+
const service = describeSyncService(view.serviceType);
|
|
35843
|
+
return /* @__PURE__ */ jsx(Fragment, { children: pieces.map((piece, index2) => {
|
|
35844
|
+
if (piece.kind === "text") {
|
|
35845
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Markdown, { children: piece.markdown }) }, index2);
|
|
35846
|
+
}
|
|
35847
|
+
if (!piece.block.viewable) {
|
|
35848
|
+
const kinds = describeHiddenKinds(piece.block.kinds);
|
|
35849
|
+
return /* @__PURE__ */ jsxs("p", { className: "my-2 border-l-2 border-line pl-3 text-sm text-text-tertiary", children: [
|
|
35850
|
+
kinds,
|
|
35851
|
+
topicParticle(kinds),
|
|
35852
|
+
" ",
|
|
35853
|
+
service,
|
|
35854
|
+
"에서 확인할 수 있습니다."
|
|
35855
|
+
] }, index2);
|
|
35856
|
+
}
|
|
35857
|
+
return /* @__PURE__ */ jsxs("div", { className: READ_ONLY_CLASS, children: [
|
|
35858
|
+
/* @__PURE__ */ jsxs("span", { className: "block text-xs text-text-tertiary", children: [
|
|
35859
|
+
service,
|
|
35860
|
+
"에서만 수정할 수 있습니다"
|
|
35861
|
+
] }),
|
|
35862
|
+
/* @__PURE__ */ jsx(Markdown, { children: piece.block.markdown })
|
|
35863
|
+
] }, index2);
|
|
35864
|
+
}) });
|
|
35865
|
+
}
|
|
35866
|
+
const fallbacks = /* @__PURE__ */ new Map();
|
|
35867
|
+
const listeners$1 = /* @__PURE__ */ new Set();
|
|
35868
|
+
function notify$1() {
|
|
35869
|
+
for (const listener of [...listeners$1]) listener();
|
|
35870
|
+
}
|
|
35871
|
+
function markFullTextFallback(issueId, signature) {
|
|
35872
|
+
if (fallbacks.get(issueId) === signature) return;
|
|
35873
|
+
fallbacks.set(issueId, signature);
|
|
35874
|
+
notify$1();
|
|
35875
|
+
}
|
|
35876
|
+
function readFullTextFallback(issueId) {
|
|
35877
|
+
return fallbacks.get(issueId);
|
|
35878
|
+
}
|
|
35879
|
+
function subscribeFullTextFallback(listener) {
|
|
35880
|
+
listeners$1.add(listener);
|
|
35881
|
+
return () => {
|
|
35882
|
+
listeners$1.delete(listener);
|
|
35883
|
+
};
|
|
35884
|
+
}
|
|
35885
|
+
const HIDES_EXTERNAL_PAYLOAD = { description_hides_external: true };
|
|
35886
|
+
const FULL_TEXT = [];
|
|
35887
|
+
function sameBasis(a, b) {
|
|
35888
|
+
return a.length === b.length && a.every((markdown, index2) => markdown === b[index2]);
|
|
35889
|
+
}
|
|
35890
|
+
function isUnrecoverableRefresh(error) {
|
|
35891
|
+
const status = error == null ? void 0 : error.status;
|
|
35892
|
+
return status === 400 || status === 404;
|
|
35893
|
+
}
|
|
35894
|
+
function useDescriptionEditing({
|
|
35895
|
+
isEditing,
|
|
35896
|
+
saveError = null,
|
|
35897
|
+
...options
|
|
35898
|
+
}) {
|
|
35899
|
+
const base = useDescriptionEditingBase(options);
|
|
35900
|
+
return { ...base, ...base.resolve({ isEditing, saveError }) };
|
|
35901
|
+
}
|
|
35902
|
+
function useDescriptionEditingBase({
|
|
35903
|
+
issueId,
|
|
35904
|
+
description,
|
|
35905
|
+
view,
|
|
35906
|
+
blocked,
|
|
35907
|
+
canEdit,
|
|
35908
|
+
refresh,
|
|
35909
|
+
reload
|
|
35910
|
+
}) {
|
|
35911
|
+
const [refreshFailure, setRefreshFailure] = useState(
|
|
35912
|
+
null
|
|
35913
|
+
);
|
|
35914
|
+
const fallbackSignature = useSyncExternalStore(
|
|
35915
|
+
subscribeFullTextFallback,
|
|
35916
|
+
() => readFullTextFallback(issueId),
|
|
35917
|
+
() => void 0
|
|
35918
|
+
);
|
|
35919
|
+
const [rejectedIssueId, setRejectedIssueId] = useState(null);
|
|
35920
|
+
const [editBasis, setEditBasis] = useState(FULL_TEXT);
|
|
35921
|
+
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
35922
|
+
const stateSignature = descriptionStateSignature(view, description);
|
|
35923
|
+
const fullText = fallbackSignature === stateSignature;
|
|
35924
|
+
const needsRefresh = !!(view == null ? void 0 : view.needsRefresh) && !blocked && !fullText;
|
|
35925
|
+
const pieces = fullText ? null : (view == null ? void 0 : view.pieces) ?? null;
|
|
35926
|
+
const hiddenBlocks = pieces == null ? void 0 : pieces.flatMap((piece) => piece.kind === "hidden" ? [piece.block] : []);
|
|
35927
|
+
const editable = (hiddenBlocks == null ? void 0 : hiddenBlocks.length) ? editableDescription(description ?? "", hiddenBlocks) : null;
|
|
35928
|
+
const hidesExternal = editable !== null;
|
|
35929
|
+
const nothingToEdit = editable === "";
|
|
35930
|
+
const currentBasis = hidesExternal ? (hiddenBlocks ?? []).map((block) => block.markdown) : FULL_TEXT;
|
|
35931
|
+
const viewKey = `${issueId}\0${view ? JSON.stringify([view.serviceType, view.needsRefresh, currentBasis]) : ""}`;
|
|
35932
|
+
const refreshMessage = (refreshFailure == null ? void 0 : refreshFailure.key) === viewKey ? refreshFailure.message : null;
|
|
35933
|
+
async function refreshDescription() {
|
|
35934
|
+
setRefreshFailure(null);
|
|
35935
|
+
setIsRefreshing(true);
|
|
35936
|
+
try {
|
|
35937
|
+
const fresh = await refresh();
|
|
35938
|
+
const freshView = readDescriptionView(fresh.issue_external_mappings, fresh.description);
|
|
35939
|
+
if (freshView == null ? void 0 : freshView.needsRefresh) {
|
|
35940
|
+
markFullTextFallback(issueId, descriptionStateSignature(freshView, fresh.description));
|
|
35941
|
+
}
|
|
35942
|
+
} catch (error) {
|
|
35943
|
+
if (isUnrecoverableRefresh(error)) markFullTextFallback(issueId, stateSignature);
|
|
35944
|
+
setRefreshFailure({
|
|
35945
|
+
message: error instanceof Error && error.message ? error.message : DESCRIPTION_REFRESH_FAILED_MESSAGE,
|
|
35946
|
+
key: viewKey
|
|
35947
|
+
});
|
|
35948
|
+
} finally {
|
|
35949
|
+
setIsRefreshing(false);
|
|
35950
|
+
}
|
|
35951
|
+
}
|
|
35952
|
+
async function handleSaveRejected({ code: code2 }) {
|
|
35953
|
+
if (code2 !== "DESCRIPTION_EXTERNAL_CHANGED" || editBasis.length === 0) return;
|
|
35954
|
+
let fresh;
|
|
35955
|
+
try {
|
|
35956
|
+
fresh = await reload();
|
|
35957
|
+
} catch {
|
|
35958
|
+
return;
|
|
35959
|
+
}
|
|
35960
|
+
if (!fresh || !isSaveRejectionRepeating({ description, basis: editBasis }, fresh)) return;
|
|
35961
|
+
markFullTextFallback(issueId, stateSignature);
|
|
35962
|
+
setRejectedIssueId(issueId);
|
|
35963
|
+
}
|
|
35964
|
+
function resolve({
|
|
35965
|
+
isEditing,
|
|
35966
|
+
saveError = null
|
|
35967
|
+
}) {
|
|
35968
|
+
const basisChanged = isEditing && !sameBasis(editBasis, currentBasis);
|
|
35969
|
+
const saveBlocked = blocked || needsRefresh || basisChanged;
|
|
35970
|
+
const rejectionActive = isEditing && rejectedIssueId === issueId;
|
|
35971
|
+
return {
|
|
35972
|
+
/** 수정 버튼을 보인다. 편집 중이 아닐 때만 뜻이 있다. */
|
|
35973
|
+
canStartEdit: canEdit && !saveBlocked && !nothingToEdit,
|
|
35974
|
+
/** 편집 중이면 편집란에서 실제로 뺀 조각이 지금과 같을 때, 아니면 모두 숨긴 설명을 편집할 수 있는 사용자에게. */
|
|
35975
|
+
showHiddenNotice: !!view && !!pieces && hidesExternal && !blocked && (isEditing ? editBasis.length > 0 && !basisChanged : nothingToEdit && canEdit),
|
|
35976
|
+
basisChanged,
|
|
35977
|
+
/** 숨긴 조각이 바뀌어 저장이 막힌 이유를 알린다. 다시 불러오기 안내와 겹치지 않게 한다. */
|
|
35978
|
+
showBasisChangedNotice: basisChanged && !needsRefresh,
|
|
35979
|
+
/** 저장이 막힌 이유. 설명이 바뀌었거나(changed), 저장이 되풀이 거절돼 전체 글로 돌아갔다(rejected). */
|
|
35980
|
+
basisChangeReason: rejectionActive ? "rejected" : "changed",
|
|
35981
|
+
saveBlocked,
|
|
35982
|
+
/**
|
|
35983
|
+
* 보여 줄 오류. 저장이 되풀이 거절됐으면 화면이 정한 문구가 먼저다. 지난 저장 오류 문구는 "최신
|
|
35984
|
+
* 내용을 불러왔다"고 하고 서버 문구는 이 화면에 없는 버튼을 가리킬 수 있어 둘 다 맞지 않는다.
|
|
35985
|
+
* 기준이 바뀐 뒤에는 지난 저장 오류가 안내와 모순이라 감춘다.
|
|
35986
|
+
*/
|
|
35987
|
+
shownError: rejectionActive ? DESCRIPTION_STRIPPED_SAVE_REJECTED_MESSAGE : basisChanged ? null : saveError ?? refreshMessage
|
|
35988
|
+
};
|
|
35989
|
+
}
|
|
35990
|
+
return {
|
|
35991
|
+
needsRefresh,
|
|
35992
|
+
/** 수정 버튼 대신 다시 불러오기 안내를 보인다. */
|
|
35993
|
+
showRefreshNotice: needsRefresh && canEdit,
|
|
35994
|
+
/** 편집을 시작할 때 편집란에 넣을 값. */
|
|
35995
|
+
startValue: editable ?? description ?? "",
|
|
35996
|
+
/** 편집란에서 뺀 조각이 있어 지금 설명에도 숨길 조각이 있다. 옛 보호 요소 안내를 대신한다. */
|
|
35997
|
+
hidesExternal,
|
|
35998
|
+
hiddenKinds: pieces ? collectHiddenKinds(pieces) : [],
|
|
35999
|
+
/** 저장할 때 함께 보낼 필드. 편집 시작 때 숨긴 조각을 뺐을 때만 있다. */
|
|
36000
|
+
extraPayload: editBasis.length > 0 ? HIDES_EXTERNAL_PAYLOAD : void 0,
|
|
36001
|
+
isRefreshing,
|
|
36002
|
+
/** 수정을 시작한다. 지금 편집란에서 뺄 조각을 기준으로 기록한다. */
|
|
36003
|
+
beginEdit() {
|
|
36004
|
+
setEditBasis(currentBasis);
|
|
36005
|
+
setRefreshFailure(null);
|
|
36006
|
+
setRejectedIssueId(null);
|
|
36007
|
+
},
|
|
36008
|
+
/**
|
|
36009
|
+
* 저장이 거절되면 부른다. 표시를 보낸 저장이 외부 변경(DESCRIPTION_EXTERNAL_CHANGED)으로 거절됐고
|
|
36010
|
+
* 이슈를 다시 받아도 설명과 숨긴 조각이 그대로면 그 이슈를 전체 글 편집으로 돌린다.
|
|
36011
|
+
*/
|
|
36012
|
+
handleSaveRejected,
|
|
36013
|
+
refreshDescription,
|
|
36014
|
+
resolve
|
|
36015
|
+
};
|
|
36016
|
+
}
|
|
36017
|
+
function errorCodeOf(err) {
|
|
36018
|
+
var _a;
|
|
36019
|
+
const error = (_a = err == null ? void 0 : err.data) == null ? void 0 : _a.error;
|
|
36020
|
+
return typeof error === "object" && error !== null ? error.code : void 0;
|
|
36021
|
+
}
|
|
36022
|
+
const REFRESH_CODES = /* @__PURE__ */ new Set(["DESCRIPTION_SYNC_LOCKED", "DESCRIPTION_EXTERNAL_CHANGED"]);
|
|
36023
|
+
function useIssueFieldUpdate(issueId, onUpdated, syncService) {
|
|
36024
|
+
const [error, setError] = useState(null);
|
|
36025
|
+
const [savingField, setSavingField] = useState(null);
|
|
36026
|
+
const updateField = useCallback(
|
|
36027
|
+
async (field, value, extra, onRejected) => {
|
|
36028
|
+
setError(null);
|
|
36029
|
+
setSavingField(field);
|
|
36030
|
+
try {
|
|
36031
|
+
await issueService.updateIssue(issueId, { ...extra, [field]: value });
|
|
36032
|
+
applyIssueMutationEffects(issueId);
|
|
36033
|
+
onUpdated == null ? void 0 : onUpdated();
|
|
36034
|
+
return true;
|
|
36035
|
+
} catch (err) {
|
|
36036
|
+
const code2 = errorCodeOf(err);
|
|
36037
|
+
setError(
|
|
36038
|
+
descriptionSyncErrorMessage(code2, syncService) ?? (err instanceof Error ? err.message : "이슈 업데이트에 실패했습니다.")
|
|
36039
|
+
);
|
|
36040
|
+
if (code2 && REFRESH_CODES.has(code2)) {
|
|
36041
|
+
applyIssueMutationEffects(issueId);
|
|
36042
|
+
onUpdated == null ? void 0 : onUpdated();
|
|
36043
|
+
}
|
|
36044
|
+
try {
|
|
36045
|
+
await (onRejected == null ? void 0 : onRejected({ code: code2 }));
|
|
36046
|
+
} catch {
|
|
36047
|
+
}
|
|
36048
|
+
return false;
|
|
36049
|
+
} finally {
|
|
36050
|
+
setSavingField((current2) => current2 === field ? null : current2);
|
|
36051
|
+
}
|
|
36052
|
+
},
|
|
36053
|
+
[issueId, onUpdated, syncService]
|
|
36054
|
+
);
|
|
36055
|
+
const clearError = useCallback(() => setError(null), []);
|
|
36056
|
+
return {
|
|
36057
|
+
error,
|
|
36058
|
+
savingField,
|
|
36059
|
+
updateField,
|
|
36060
|
+
clearError
|
|
36061
|
+
};
|
|
36062
|
+
}
|
|
35124
36063
|
function IssueDescription({
|
|
35125
36064
|
issueId,
|
|
35126
36065
|
description,
|
|
35127
36066
|
onUpdated,
|
|
35128
|
-
readOnly = false
|
|
36067
|
+
readOnly = false,
|
|
36068
|
+
syncLock,
|
|
36069
|
+
view,
|
|
36070
|
+
externalUrl,
|
|
36071
|
+
onRefreshDescription,
|
|
36072
|
+
onReloadIssue
|
|
35129
36073
|
}) {
|
|
35130
36074
|
const textareaRef = useRef(null);
|
|
35131
36075
|
const [draftDescription, setDraftDescription] = useState(description);
|
|
35132
36076
|
const [isEditing, setIsEditing] = useState(false);
|
|
35133
|
-
const { error, savingField, updateField } = useIssueFieldUpdate(
|
|
36077
|
+
const { error, savingField, updateField, clearError } = useIssueFieldUpdate(
|
|
36078
|
+
issueId,
|
|
36079
|
+
onUpdated,
|
|
36080
|
+
(syncLock == null ? void 0 : syncLock.serviceType) ?? (view == null ? void 0 : view.serviceType)
|
|
36081
|
+
);
|
|
36082
|
+
const blocked = !!(syncLock == null ? void 0 : syncLock.blocksEditing);
|
|
36083
|
+
const editing = useDescriptionEditing({
|
|
36084
|
+
issueId,
|
|
36085
|
+
description,
|
|
36086
|
+
view,
|
|
36087
|
+
blocked,
|
|
36088
|
+
canEdit: !readOnly,
|
|
36089
|
+
isEditing,
|
|
36090
|
+
saveError: error,
|
|
36091
|
+
refresh: onRefreshDescription,
|
|
36092
|
+
reload: onReloadIssue
|
|
36093
|
+
});
|
|
35134
36094
|
useEffect(() => {
|
|
35135
|
-
setDraftDescription(description);
|
|
35136
|
-
}, [description]);
|
|
36095
|
+
if (!isEditing) setDraftDescription(description);
|
|
36096
|
+
}, [description, isEditing]);
|
|
35137
36097
|
const handleStartEdit = () => {
|
|
35138
|
-
|
|
36098
|
+
editing.beginEdit();
|
|
36099
|
+
clearError();
|
|
36100
|
+
setDraftDescription(editing.startValue);
|
|
35139
36101
|
setIsEditing(true);
|
|
35140
36102
|
};
|
|
35141
36103
|
const handleCancelEdit = () => {
|
|
36104
|
+
clearError();
|
|
35142
36105
|
setDraftDescription(description);
|
|
35143
36106
|
setIsEditing(false);
|
|
35144
36107
|
};
|
|
35145
36108
|
const handleSave = async () => {
|
|
35146
|
-
|
|
36109
|
+
if (readOnly || editing.saveBlocked) {
|
|
36110
|
+
return;
|
|
36111
|
+
}
|
|
36112
|
+
const extra = editing.extraPayload;
|
|
36113
|
+
const success = await updateField(
|
|
36114
|
+
"description",
|
|
36115
|
+
draftDescription.trim(),
|
|
36116
|
+
extra,
|
|
36117
|
+
// 뺀 초안의 저장이 같은 이유로 계속 거절되는지는 거절 코드를 보고 이슈를 다시 받아 정한다.
|
|
36118
|
+
extra ? editing.handleSaveRejected : void 0
|
|
36119
|
+
);
|
|
35147
36120
|
if (success) {
|
|
35148
36121
|
setIsEditing(false);
|
|
35149
36122
|
}
|
|
@@ -35160,7 +36133,7 @@ function IssueDescription({
|
|
|
35160
36133
|
variant: "secondary",
|
|
35161
36134
|
size: "sm",
|
|
35162
36135
|
onClick: handleSave,
|
|
35163
|
-
disabled: isSaving,
|
|
36136
|
+
disabled: isSaving || editing.saveBlocked,
|
|
35164
36137
|
children: isSaving ? "저장 중..." : "저장"
|
|
35165
36138
|
}
|
|
35166
36139
|
),
|
|
@@ -35175,7 +36148,7 @@ function IssueDescription({
|
|
|
35175
36148
|
children: "취소"
|
|
35176
36149
|
}
|
|
35177
36150
|
)
|
|
35178
|
-
] }) :
|
|
36151
|
+
] }) : editing.canStartEdit ? /* @__PURE__ */ jsx(
|
|
35179
36152
|
Button,
|
|
35180
36153
|
{
|
|
35181
36154
|
type: "button",
|
|
@@ -35187,20 +36160,40 @@ function IssueDescription({
|
|
|
35187
36160
|
}
|
|
35188
36161
|
) : null
|
|
35189
36162
|
] }),
|
|
36163
|
+
syncLock && (blocked || !editing.hidesExternal && !editing.showRefreshNotice) ? /* @__PURE__ */ jsx(DescriptionSyncLockNotice, { lock: syncLock, canEdit: !readOnly }) : null,
|
|
36164
|
+
editing.showRefreshNotice ? /* @__PURE__ */ jsx(
|
|
36165
|
+
DescriptionRefreshNotice,
|
|
36166
|
+
{
|
|
36167
|
+
onRefresh: () => void editing.refreshDescription(),
|
|
36168
|
+
isRefreshing: editing.isRefreshing
|
|
36169
|
+
}
|
|
36170
|
+
) : null,
|
|
36171
|
+
view && editing.showHiddenNotice ? /* @__PURE__ */ jsx(
|
|
36172
|
+
HiddenDescriptionNotice,
|
|
36173
|
+
{
|
|
36174
|
+
serviceType: view.serviceType,
|
|
36175
|
+
kinds: editing.hiddenKinds,
|
|
36176
|
+
externalUrl
|
|
36177
|
+
}
|
|
36178
|
+
) : null,
|
|
36179
|
+
editing.showBasisChangedNotice ? /* @__PURE__ */ jsx(DescriptionEditBasisChangedNotice, { reason: editing.basisChangeReason }) : null,
|
|
35190
36180
|
isEditing ? /* @__PURE__ */ jsx(
|
|
35191
36181
|
Textarea,
|
|
35192
36182
|
{
|
|
35193
36183
|
ref: textareaRef,
|
|
35194
36184
|
value: draftDescription,
|
|
35195
|
-
onChange: (event) =>
|
|
36185
|
+
onChange: (event) => {
|
|
36186
|
+
setDraftDescription(event.target.value);
|
|
36187
|
+
clearError();
|
|
36188
|
+
},
|
|
35196
36189
|
placeholder: "설명을 입력하세요",
|
|
35197
36190
|
rows: 6,
|
|
35198
36191
|
disabled: isSaving,
|
|
35199
36192
|
className: "min-h-[140px] resize-none overflow-y-auto",
|
|
35200
36193
|
"aria-label": "설명 입력"
|
|
35201
36194
|
}
|
|
35202
|
-
) : description ? /* @__PURE__ */ jsx("div", { className: "text-sm leading-relaxed text-text-primary", children: /* @__PURE__ */ jsx(
|
|
35203
|
-
|
|
36195
|
+
) : description ? /* @__PURE__ */ jsx("div", { className: "text-sm leading-relaxed text-text-primary", children: /* @__PURE__ */ jsx(IssueDescriptionView, { description, view }) }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-text-tertiary", children: "설명이 아직 없습니다." }),
|
|
36196
|
+
editing.shownError ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-xs text-danger", children: editing.shownError }) : null
|
|
35204
36197
|
] });
|
|
35205
36198
|
}
|
|
35206
36199
|
function getServiceDisplayName(serviceType) {
|
|
@@ -35468,18 +36461,20 @@ function IssueHeader({
|
|
|
35468
36461
|
const [draftTitle, setDraftTitle] = useState(title);
|
|
35469
36462
|
const [isEditing, setIsEditing] = useState(false);
|
|
35470
36463
|
const [validationError, setValidationError] = useState(null);
|
|
35471
|
-
const { error, savingField, updateField } = useIssueFieldUpdate(issueId, onUpdated);
|
|
36464
|
+
const { error, savingField, updateField, clearError } = useIssueFieldUpdate(issueId, onUpdated);
|
|
35472
36465
|
useEffect(() => {
|
|
35473
36466
|
setDraftTitle(title);
|
|
35474
36467
|
}, [title]);
|
|
35475
36468
|
const handleStartEdit = () => {
|
|
35476
36469
|
setDraftTitle(title);
|
|
35477
36470
|
setValidationError(null);
|
|
36471
|
+
clearError();
|
|
35478
36472
|
setIsEditing(true);
|
|
35479
36473
|
};
|
|
35480
36474
|
const handleCancelEdit = () => {
|
|
35481
36475
|
setDraftTitle(title);
|
|
35482
36476
|
setValidationError(null);
|
|
36477
|
+
clearError();
|
|
35483
36478
|
setIsEditing(false);
|
|
35484
36479
|
};
|
|
35485
36480
|
const handleSave = async () => {
|
|
@@ -35508,6 +36503,7 @@ function IssueHeader({
|
|
|
35508
36503
|
value: draftTitle,
|
|
35509
36504
|
onChange: (event) => {
|
|
35510
36505
|
setDraftTitle(event.target.value);
|
|
36506
|
+
clearError();
|
|
35511
36507
|
if (validationError) {
|
|
35512
36508
|
setValidationError(null);
|
|
35513
36509
|
}
|
|
@@ -36240,6 +37236,7 @@ function getOmittedReasonLabel(reason) {
|
|
|
36240
37236
|
if (reason === "transport-budget") return "전송 용량 예산 초과";
|
|
36241
37237
|
if (reason === "unavailable") return "수집 불가";
|
|
36242
37238
|
if (reason === "mime-type") return "본문을 저장하지 않는 형식";
|
|
37239
|
+
if (reason === "masking-policy") return MASKING_COPY.maskedLabel;
|
|
36243
37240
|
return reason;
|
|
36244
37241
|
}
|
|
36245
37242
|
function OmittedBodyInfo({
|
|
@@ -36439,7 +37436,7 @@ function BodyTab({
|
|
|
36439
37436
|
if (omittedBody) {
|
|
36440
37437
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
36441
37438
|
/* @__PURE__ */ jsx(OmittedBodyInfo, { bodyType, ...omittedBody }),
|
|
36442
|
-
bodyType === "response" && log && isImageMimeType(getResponseMimeType(log)) && /* @__PURE__ */ jsx(RemoteImagePreview, { url: log.url })
|
|
37439
|
+
bodyType === "response" && log && omittedBody.reason !== "masking-policy" && isImageMimeType(getResponseMimeType(log)) && /* @__PURE__ */ jsx(RemoteImagePreview, { url: log.url })
|
|
36443
37440
|
] });
|
|
36444
37441
|
}
|
|
36445
37442
|
return /* @__PURE__ */ jsx("div", { className: "text-sm text-text-tertiary", children: emptyMessage });
|
|
@@ -36781,22 +37778,26 @@ function canWriteIssueContent(isMember, externalUserId) {
|
|
|
36781
37778
|
return Boolean(externalUserId);
|
|
36782
37779
|
}
|
|
36783
37780
|
function IssuePopover({ issueId, onClose, onUpdate }) {
|
|
36784
|
-
var _a;
|
|
37781
|
+
var _a, _b2;
|
|
36785
37782
|
const [isOpen, setIsOpen] = useState(true);
|
|
36786
37783
|
const [activeLogSection, setActiveLogSection] = useState(null);
|
|
36787
37784
|
const isLogDetailActive = activeLogSection !== null;
|
|
36788
37785
|
const handleNetworkDetailActiveChange = useCallback((active) => {
|
|
36789
|
-
setActiveLogSection((
|
|
37786
|
+
setActiveLogSection((current2) => active ? "network" : current2 === "network" ? null : current2);
|
|
36790
37787
|
}, []);
|
|
36791
37788
|
const handleConsoleDetailActiveChange = useCallback((active) => {
|
|
36792
|
-
setActiveLogSection((
|
|
37789
|
+
setActiveLogSection((current2) => active ? "console" : current2 === "console" ? null : current2);
|
|
36793
37790
|
}, []);
|
|
36794
37791
|
const handleClose = () => setIsOpen(false);
|
|
36795
37792
|
const { isMember } = useAuthContext();
|
|
36796
37793
|
const canWriteContent = canWriteIssueContent(isMember, (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id);
|
|
36797
37794
|
const { selectedProjectId } = useProject();
|
|
37795
|
+
const issueQueryKey = useMemo(
|
|
37796
|
+
() => ["issue", issueId, selectedProjectId],
|
|
37797
|
+
[issueId, selectedProjectId]
|
|
37798
|
+
);
|
|
36798
37799
|
const { data: issue, refetch } = useSuspenseQuery({
|
|
36799
|
-
queryKey:
|
|
37800
|
+
queryKey: issueQueryKey,
|
|
36800
37801
|
queryFn: async () => {
|
|
36801
37802
|
const issueData = await issueService.getIssue(issueId);
|
|
36802
37803
|
return issueData;
|
|
@@ -36819,6 +37820,13 @@ function IssuePopover({ issueId, onClose, onUpdate }) {
|
|
|
36819
37820
|
const hasLinkedJiraIssue = Boolean(isMember && (mapping == null ? void 0 : mapping.integration_id) && linkedJiraIssueKey);
|
|
36820
37821
|
const { isSyncingAll, syncAllFromJira, canSync } = useJiraIssueSync(issue);
|
|
36821
37822
|
const notionMapping = getPrimaryNotionMapping(issue);
|
|
37823
|
+
const syncLock = readDescriptionSyncLock(issue.issue_external_mappings);
|
|
37824
|
+
const descriptionView = readDescriptionView(issue.issue_external_mappings, issue.description);
|
|
37825
|
+
const { refresh: refreshDescription, reload: reloadIssue } = useRefreshIssueDescription(
|
|
37826
|
+
issue.id,
|
|
37827
|
+
issueQueryKey,
|
|
37828
|
+
onUpdate
|
|
37829
|
+
);
|
|
36822
37830
|
const showNotionInfo = Boolean(isMember && (notionMapping == null ? void 0 : notionMapping.integration_id));
|
|
36823
37831
|
return createPortal(
|
|
36824
37832
|
/* @__PURE__ */ jsxs(
|
|
@@ -36849,7 +37857,16 @@ function IssuePopover({ issueId, onClose, onUpdate }) {
|
|
|
36849
37857
|
issueId: issue.id,
|
|
36850
37858
|
description: issue.description ?? "",
|
|
36851
37859
|
onUpdated: onUpdate,
|
|
36852
|
-
readOnly: !canWriteContent
|
|
37860
|
+
readOnly: !canWriteContent,
|
|
37861
|
+
syncLock,
|
|
37862
|
+
view: descriptionView,
|
|
37863
|
+
externalUrl: isMember ? descriptionExternalUrl(
|
|
37864
|
+
issue,
|
|
37865
|
+
descriptionView == null ? void 0 : descriptionView.serviceType,
|
|
37866
|
+
(_b2 = jiraService.getConfig()) == null ? void 0 : _b2.siteUrl
|
|
37867
|
+
) : null,
|
|
37868
|
+
onRefreshDescription: refreshDescription,
|
|
37869
|
+
onReloadIssue: reloadIssue
|
|
36853
37870
|
}
|
|
36854
37871
|
),
|
|
36855
37872
|
showJiraInfo && mapping ? /* @__PURE__ */ jsx(
|
|
@@ -37052,16 +38069,16 @@ function isVisible(element2) {
|
|
|
37052
38069
|
function isRendered(node2) {
|
|
37053
38070
|
if (!isVisible(node2)) return false;
|
|
37054
38071
|
const view = node2.ownerDocument.defaultView;
|
|
37055
|
-
let
|
|
37056
|
-
for (let depth = 0;
|
|
37057
|
-
if (
|
|
38072
|
+
let current2 = node2;
|
|
38073
|
+
for (let depth = 0; current2 && depth < HIDDEN_ANCESTOR_LIMIT; depth += 1) {
|
|
38074
|
+
if (current2.hasAttribute("hidden") || current2.getAttribute("aria-hidden") === "true") {
|
|
37058
38075
|
return false;
|
|
37059
38076
|
}
|
|
37060
|
-
if (
|
|
37061
|
-
const style = view == null ? void 0 : view.getComputedStyle(
|
|
38077
|
+
if (current2.localName === "dialog" && !current2.hasAttribute("open")) return false;
|
|
38078
|
+
const style = view == null ? void 0 : view.getComputedStyle(current2);
|
|
37062
38079
|
if ((style == null ? void 0 : style.display) === "none") return false;
|
|
37063
|
-
if (
|
|
37064
|
-
|
|
38080
|
+
if (current2 === node2 && (style == null ? void 0 : style.visibility) === "hidden") return false;
|
|
38081
|
+
current2 = current2.parentElement;
|
|
37065
38082
|
}
|
|
37066
38083
|
return true;
|
|
37067
38084
|
}
|
|
@@ -37926,7 +38943,7 @@ function useDocumentLayoutVersion(enabled, mode) {
|
|
|
37926
38943
|
let frame2 = 0;
|
|
37927
38944
|
const bump = () => {
|
|
37928
38945
|
frame2 = 0;
|
|
37929
|
-
setVersion((
|
|
38946
|
+
setVersion((current2) => current2 + 1);
|
|
37930
38947
|
};
|
|
37931
38948
|
const scheduleFrame = () => {
|
|
37932
38949
|
if (frame2) return;
|
|
@@ -38025,7 +39042,7 @@ function IssueStickersContainer$1({
|
|
|
38025
39042
|
useEffect(() => {
|
|
38026
39043
|
if (retryAt === void 0) return void 0;
|
|
38027
39044
|
const timer = window.setTimeout(
|
|
38028
|
-
() => setRetryVersion((
|
|
39045
|
+
() => setRetryVersion((current2) => current2 + 1),
|
|
38029
39046
|
Math.max(0, retryAt - Date.now()) + 1
|
|
38030
39047
|
);
|
|
38031
39048
|
return () => window.clearTimeout(timer);
|
|
@@ -38532,7 +39549,7 @@ function useContentAppState() {
|
|
|
38532
39549
|
showToast
|
|
38533
39550
|
} = useIssueMode();
|
|
38534
39551
|
const screenRecording = useScreenRecording();
|
|
38535
|
-
const { clickPosition, clearClickPosition } = useClickPosition(
|
|
39552
|
+
const { clickPosition, clearClickPosition, recaptureScreenshots } = useClickPosition(
|
|
38536
39553
|
isCreatingIssueRef,
|
|
38537
39554
|
screenRecording.recordedFile
|
|
38538
39555
|
);
|
|
@@ -38694,14 +39711,24 @@ function useContentAppState() {
|
|
|
38694
39711
|
}
|
|
38695
39712
|
}, [isCreatingIssue]);
|
|
38696
39713
|
const handleIssueCreated = useCallback(
|
|
38697
|
-
async (hasIntegrationFailure = false) => {
|
|
38698
|
-
const hadVideo = Boolean(clickPosition == null ? void 0 : clickPosition.videoFile);
|
|
39714
|
+
async (hasIntegrationFailure = false, outcome) => {
|
|
39715
|
+
const hadVideo = Boolean(clickPosition == null ? void 0 : clickPosition.videoFile) && !(outcome == null ? void 0 : outcome.videoExcluded);
|
|
39716
|
+
const policyNotice = maskingCompletionNotice(outcome);
|
|
38699
39717
|
clearClickPosition();
|
|
38700
39718
|
screenRecording.clearRecordedFile();
|
|
38701
39719
|
await loadIssues();
|
|
38702
39720
|
await toggleIssueMode(false);
|
|
38703
39721
|
if (!hasIntegrationFailure) {
|
|
38704
|
-
|
|
39722
|
+
const message = hadVideo ? VIDEO_UPLOAD_COPY.created : "이슈가 생성되었습니다.";
|
|
39723
|
+
if (policyNotice) {
|
|
39724
|
+
toast.success(`${message} ${policyNotice}`, {
|
|
39725
|
+
duration: MASKING_NOTICE_TOAST_DURATION_MS
|
|
39726
|
+
});
|
|
39727
|
+
} else {
|
|
39728
|
+
showToast(message);
|
|
39729
|
+
}
|
|
39730
|
+
} else if (policyNotice) {
|
|
39731
|
+
toast.warning(policyNotice, { duration: MASKING_NOTICE_TOAST_DURATION_MS });
|
|
38705
39732
|
}
|
|
38706
39733
|
},
|
|
38707
39734
|
[clickPosition, clearClickPosition, loadIssues, screenRecording, toggleIssueMode, showToast]
|
|
@@ -38725,6 +39752,7 @@ function useContentAppState() {
|
|
|
38725
39752
|
handleIssueCreated,
|
|
38726
39753
|
loadIssues,
|
|
38727
39754
|
clearClickPosition,
|
|
39755
|
+
recaptureScreenshots,
|
|
38728
39756
|
toggleIssueMode,
|
|
38729
39757
|
handleToggleRecording,
|
|
38730
39758
|
screenRecordingClearRecordedFile: screenRecording.clearRecordedFile,
|
|
@@ -39800,9 +40828,9 @@ function Toolbar({
|
|
|
39800
40828
|
((_a = rootRef.current) == null ? void 0 : _a.querySelectorAll(".toolbar-btn")) ?? []
|
|
39801
40829
|
);
|
|
39802
40830
|
if (buttons.length === 0) return;
|
|
39803
|
-
const
|
|
40831
|
+
const current2 = buttons.indexOf(document.activeElement);
|
|
39804
40832
|
const delta = e.key === "ArrowRight" ? 1 : -1;
|
|
39805
|
-
const next = (
|
|
40833
|
+
const next = (current2 + delta + buttons.length) % buttons.length;
|
|
39806
40834
|
(_b2 = buttons[next]) == null ? void 0 : _b2.focus();
|
|
39807
40835
|
e.preventDefault();
|
|
39808
40836
|
}, []);
|
|
@@ -40095,6 +41123,7 @@ function ContentAppWrapper({
|
|
|
40095
41123
|
handleIssueCreated,
|
|
40096
41124
|
loadIssues,
|
|
40097
41125
|
clearClickPosition,
|
|
41126
|
+
recaptureScreenshots,
|
|
40098
41127
|
toggleIssueMode,
|
|
40099
41128
|
handleToggleRecording,
|
|
40100
41129
|
screenRecordingClearRecordedFile,
|
|
@@ -40204,7 +41233,9 @@ function ContentAppWrapper({
|
|
|
40204
41233
|
}
|
|
40205
41234
|
},
|
|
40206
41235
|
activeIntegration,
|
|
40207
|
-
isIntegrationLoading
|
|
41236
|
+
isIntegrationLoading,
|
|
41237
|
+
onScreenRulesChanged: recaptureScreenshots,
|
|
41238
|
+
recaptureScreenshots
|
|
40208
41239
|
}
|
|
40209
41240
|
) })
|
|
40210
41241
|
]
|
|
@@ -40246,7 +41277,7 @@ function AuthGate() {
|
|
|
40246
41277
|
) })
|
|
40247
41278
|
] });
|
|
40248
41279
|
}
|
|
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}`;
|
|
41280
|
+
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}.collapse{visibility:collapse}.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}.inline-table{display:inline-table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-column{display:table-column}.table-column-group{display:table-column-group}.table-footer-group{display:table-footer-group}.table-header-group{display:table-header-group}.table-row-group{display:table-row-group}.table-row{display:table-row}.flow-root{display:flow-root}.grid{display:grid}.inline-grid{display:inline-grid}.contents{display:contents}.list-item{display:list-item}.\\!hidden{display:none!important}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.size-3{width:12px;height:12px}.size-4{width:16px;height:16px}.\\!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{flex-shrink:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.flex-grow,.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-3{-moz-column-gap:12px;column-gap:12px}.gap-x-5{-moz-column-gap:20px;column-gap:20px}.gap-y-1{row-gap:4px}.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}.self-end{align-self:flex-end}.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-6{padding-left:24px}.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)!important}.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))}.\\[\\&_\\:is\\(h1\\,h2\\,h3\\,h4\\,h5\\,h6\\,p\\,li\\,td\\,th\\,summary\\,blockquote\\)\\]\\:text-text-secondary :is(h1,h2,h3,h4,h5,h6,p,li,td,th,summary,blockquote){--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.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}`;
|
|
40250
41281
|
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}";
|
|
40251
41282
|
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}}`;
|
|
40252
41283
|
const PAGE_STYLE_ID = "issue-sticker-page-style";
|