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.
@@ -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, d as usePortalContainer, a as cn$1, e as OVERLAY_LAYER, s as stopEscapePropagation, f as useControllableState, g as useId$1, P as Presence, h as Primitive, i as composeEventHandlers, j as useDismissableLayerSurface, k as useComposedRefs$1, l as Portal$1, m as createContextScope, n as createSlot, D as DismissableLayer, o as useLayoutEffect2, p as useCallbackRef, u as ungzip_1, q as PortalContainerProvider, r as registerThree } from "./three-B228j4M6.js";
19
- import { L as toast, M as trimLogBackupPayload, O as createSafeLogBackup, P as getLogBackupSessionId, N as NetworkCollector, C as ConsoleCollector, W as WebSocketCollector, Q as createIndexedDbLogBackup, e as buildJiraCreateFields, R as Popover, T as PopoverTrigger, U as Input, X as PopoverContent, Y as Label, Z as Select, _ as SelectTrigger, $ as SelectValue, a0 as SelectContent, a1 as SelectItem, a2 as JIRA_ISSUE_TYPE_VALUE_KEY, a3 as getJiraMetadata, a4 as buildJiraIssueFields, a5 as getJiraIssueTypeLabel, a6 as Button, a7 as Root2$2, a8 as Trigger$2, a9 as ChevronDown, aa as Portal, ab as Content2$1, ac as Check, ad as X$1, ae as DatePicker, f as buildNotionCreateFields, af as getNotionPageMetadata, ag as buildNotionFieldViews, b as captureWithModernScreenshot, p as pristineFetch, d as directUploadToSignedUrl, ah as DirectUploadError, a as uploadSignedMediaWithApi, v as sanitizeString, ai as getRegisteredUploadId, h as buildGuestOwnerQuery, z as createIssueUploadQueues, G as loadTusClient, H as createIndexedDbPendingUploadStore, K as createMediaUploadApi, J as ATTACHMENT_UPLOAD_DB_NAME, V as VIDEO_UPLOAD_DB_NAME, aj as getSnapshot, ak as subscribe$1, k as devLogger, y as getCurrentPageUrl, al as ChevronRight, am as ReactRemoveScroll, an as hideOthers, ao as useFocusGuards, ap as FocusScope, aq as createShadowDismissRoot, ar as getExposedJiraFields, as as isJiraFieldExposed, at as normalizeExposedJiraFields, c as captureViewportWithElementCrop, B as preloadModernScreenshot, g as getElementPosition, u as uploadScreenshotDataUrls, l as filterExcludeServiceRelatedLogs, m as filterExcludeServiceRelatedConsoleLogs, s as selectNetworkLogsForSubmit, n as compactNetworkLogsForTransport, o as CONSOLE_LOG_SUBMIT_LIMIT, q as buildExternalUserPayload, w as collectAttachmentUploads, x as hasReplayUpload, r as shrinkNetworkLogsToFit, t as measureJsonBytes, j as buildIssueIntegrationsPayload, D as enqueueIssueUploads, E as normalizeUploadMimeType, A as SessionReplayCaptureController, au as resolveJiraIssueTypeId, av as pickJiraIssueTypeFields, aw as switchJiraIssueType, ax as getPrimaryJiraMapping, ay as createCollection, az as useDirection, aA as useShadowOutsideDismiss, aB as getPrimaryNotionMapping, aC as buttonVariants, aD as TEST_ATTR_KEYS, aE as jaccard, aF as textSimilarity, aG as collectHeadings, aH as buildElementLocator, aI as normalizeForCompare, aJ as CONTAINER_SELECTOR, aK as safeRole, aL as safeAccessibleName, aM as sameDigitGroups, aN as labelSimilarityKeepingDigits, aO as landmarkRole, aP as findElementBySelector, aQ as findElementByXPath, S as ScreenRecordingController, i as composeIssueFilterGroups, aR as OnboardingProvider, aS as useOnboardingTarget, aT as useOnboardingFlow, aU as PopoverAnchor } from "./externalUserPayload-DWcXyz2U.js";
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-CT7e9xbU.js";
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 current = states.find((state) => state.status === "uploading");
32
- const percent2 = current && current.bytesTotal > 0 ? Math.floor(current.bytesSent / current.bytesTotal * 100) : 0;
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
- const aborted = visibleKinds(notice.aborted);
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 pending = __privateSet(this, _currentThenable, nextResult.promise = pendingThenable());
3867
- finalizeThenableIfPossible(pending);
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 captureWithModernScreenshot({
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 captureWithModernScreenshot({
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 current = stateRef.current;
6531
- const tenantId = ((_a = result.context) == null ? void 0 : _a.tenantId) || current.tenantId;
6532
- const projectId = ((_b2 = result.context) == null ? void 0 : _b2.projectId) || current.projectId;
6533
- const accountId = ((_c2 = result.context) == null ? void 0 : _c2.accountId) || current.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 pending = pendingRequestsRef.current.get(message.requestId);
6707
- if (!pending) return;
6708
- window.clearTimeout(pending.timeoutId);
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
- pending.resolve(message.data);
7040
+ pending2.resolve(message.data);
6712
7041
  } else {
6713
- pending.reject(new Error(((_b2 = message.error) == null ? void 0 : _b2.message) || ((_c2 = message.error) == null ? void 0 : _c2.code) || "Auth failed"));
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 current2 = target - envelope * (A * sin + initialDelta * cos);
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 - current2) <= restDelta;
7879
- state.value = state.done ? target : current2;
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 current = resolveSpring(t);
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 - current) <= restDelta;
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 : current;
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, current) {
8239
+ function getGeneratorVelocity(resolveValue, t, current2) {
7911
8240
  const prevT = Math.max(t - velocitySampleDuration, 0);
7912
- return /* @__PURE__ */ velocityPerSecond(current - resolveValue(prevT), t - prevT);
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 current = this.generator.next(t).value;
8290
- return getGeneratorVelocity((s) => this.generator.next(s).value, t, current);
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 current = sampleAnimation.sample(sampleTime).value;
9248
+ const current2 = sampleAnimation.sample(sampleTime).value;
8920
9249
  const { name: name2 } = this.options;
8921
9250
  if (element2 && name2)
8922
- setStyle(element2, name2, current);
8923
- motionValue2.setWithVelocity(sampleAnimation.sample(Math.max(0, sampleTime - delta)).value, current, delta);
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 current = keyframes2[0];
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] !== current)
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(current) {
9204
- this.current = current;
9532
+ setCurrent(current2) {
9533
+ this.current = current2;
9205
9534
  this.updatedAt = time.now();
9206
- if (this.canTrackVelocity === null && current !== void 0) {
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, current, delta) {
9309
- this.set(current);
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(current) {
9568
- const match = splitCSSVariableRegex.exec(current);
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(current, element2, depth = 1) {
9576
- invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`, "max-css-var-depth");
9577
- const [token, fallback] = parseCSSVariable(current);
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 [current, velocity] = getValueState(visualElement);
9598
- definition2 = definition2(custom !== void 0 ? custom : props.custom, current, velocity);
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 [current, velocity] = getValueState(visualElement);
9605
- definition2 = definition2(custom !== void 0 ? custom : props.custom, current, velocity);
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 current ? current.ownerDocument.defaultView : null;
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 current = element2.parentElement;
14079
- while (current) {
14080
- const style = getComputedStyle(current);
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(current, {
14083
- x: current.scrollLeft,
14084
- y: current.scrollTop
14411
+ this.scrollPositions.set(current2, {
14412
+ x: current2.scrollLeft,
14413
+ y: current2.scrollTop
14085
14414
  });
14086
14415
  }
14087
- current = current.parentElement;
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 current = isWindow ? { x: window.scrollX, y: window.scrollY } : {
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: current.x - initial.x, y: current.y - initial.y };
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, current);
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 current = this.getAxisMotionValue(axis).get() || 0;
14322
- if (percent.test(current)) {
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
- current = length * (parseFloat(current) / 100);
14657
+ current2 = length * (parseFloat(current2) / 100);
14329
14658
  }
14330
14659
  }
14331
14660
  }
14332
- this.originPoint[axis] = current;
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 current = axisValue.get() || 0;
14551
- axisValue.set(point2[axis] - mixNumber$1(min, max, 0.5) + current);
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 (!current)
15211
+ const { current: current2 } = this.node;
15212
+ if (!current2)
14884
15213
  return;
14885
- this.unmount = hover(current, (_element, startEvent) => {
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 (!current)
15267
+ const { current: current2 } = this.node;
15268
+ if (!current2)
14940
15269
  return;
14941
15270
  const { globalTapTarget, propagate } = this.node.props;
14942
- this.unmount = press(current, (_element, startEvent) => {
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: pending,
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 && (pending == null ? void 0 : pending.some((project) => project.projectId === 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 captureViewportWithElementCrop({ element: element2, excludeSelectors });
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 toScreenshotList(dataUrls, dataUrl) {
16826
- if (dataUrls && dataUrls.length > 0) {
16827
- return dataUrls;
16828
- }
16829
- return dataUrl ? [dataUrl] : [];
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 resolveClickPositionScreenshots(position2) {
16832
- const immediate = toScreenshotList(position2.screenshotDataUrls, position2.screenshotDataUrl);
16833
- if (immediate.length > 0) {
16834
- return immediate;
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 { fullScreenshotDataUrl, elementScreenshotDataUrl } = await pauseNetworkLogCollectionWhile(async () => {
16947
- const { fullDataUrl, elementDataUrl } = await captureViewportAndElement(
16948
- position2.element,
16949
- SCREENSHOT_EXCLUDE_SELECTORS
16950
- );
16951
- const element2 = elementDataUrl ?? await captureScreenshot({
16952
- element: position2.element,
16953
- excludeSelectors: SCREENSHOT_EXCLUDE_SELECTORS
16954
- });
16955
- return { fullScreenshotDataUrl: fullDataUrl, elementScreenshotDataUrl: element2 };
16956
- });
16957
- const captured = {
16958
- screenshotDataUrl: elementScreenshotDataUrl,
16959
- screenshotDataUrls: [fullScreenshotDataUrl, elementScreenshotDataUrl].filter(
16960
- (dataUrl) => typeof dataUrl === "string" && dataUrl.length > 0
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 = captureScreenshotsInBackground(newClickPosition);
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 uploadScreenshot(screenshotDataUrl, issueId, options) {
17047
- const [firstUrl] = await uploadScreenshots([screenshotDataUrl], issueId, options);
17048
- if (typeof firstUrl === "string" && firstUrl.length > 0) {
17049
- return firstUrl;
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
- throw new Error("스크린샷 업로드 응답에 URL이 없습니다.");
17500
+ return { screenshotUrls, replay, screenshotExcluded };
17052
17501
  }
17053
- async function uploadScreenshots(screenshotDataUrls, issueId, options) {
17054
- const uploads = await uploadScreenshotDataUrls(
17055
- screenshotDataUrls,
17056
- uploadSignedMedia,
17057
- issueId,
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 useScreenshotUpload() {
17063
- const upload = async (screenshotDataUrl, options) => {
17064
- try {
17065
- const screenshotUrl = await uploadScreenshot(screenshotDataUrl, void 0, options);
17066
- return screenshotUrl;
17067
- } catch {
17068
- return void 0;
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, _b2, _c2, _d2, _e2, _f2;
17547
+ var _a;
17111
17548
  assertSubmittable(data);
17112
- let screenshotUrls;
17113
17549
  const videoFile2 = data.videoFile ?? data.position.videoFile;
17114
- if (!videoFile2) {
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 issueService.createIssue({ ...issueData, integrations });
17199
- if (videoFile2 || attachments.length > 0) {
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: videoFile2 ? { blob: videoFile2, mimeType: normalizeUploadMimeType(videoFile2.type, "video") } : null,
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 (((_f2 = data.intent) == null ? void 0 : _f2.trim()) && createdIssue.generation_status === "skipped") {
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: createIssueMutation.error ? `이슈 생성에 실패했습니다: ${createIssueMutation.error instanceof Error ? createIssueMutation.error.message : "알 수 없는 오류"}` : null
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 takeSnapshot = useCallback(async () => {
17407
- return controller.takeSnapshot();
17408
- }, [controller]);
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 controller = useSessionReplayController();
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((current) => ({ ...current, [fieldDefinitionId]: value }));
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
- (current) => switchJiraIssueType(current, {
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
- onSubmit: (hasIntegrationFailure) => {
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((current) => ({ ...defaults, ...current }))
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((current) => ({ ...defaults, ...current }))
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((current) => ({
18364
- ...current,
18921
+ setJiraFields((current2) => ({
18922
+ ...current2,
18365
18923
  [fieldId]: value
18366
18924
  }));
18367
18925
  },
18368
- onDefaultsResolved: (defaults) => setJiraFields((current) => ({ ...defaults, ...current })),
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((current) => ({
18393
- ...current,
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((current) => ({ ...current, [fieldId]: value })),
18408
- onDefaultsResolved: (defaults) => setCustomFieldValues((current) => ({ ...defaults, ...current }))
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 current = token;
26623
+ let current2 = token;
25895
26624
  let adjust = 0;
25896
26625
  let start = 0;
25897
26626
  const breaks = [start];
25898
- while (current) {
25899
- while (events.get(++startPosition)[1] !== current) {
26627
+ while (current2) {
26628
+ while (events.get(++startPosition)[1] !== current2) {
25900
26629
  }
25901
26630
  startPositions.push(startPosition);
25902
- if (!current._tokenizer) {
25903
- stream = context.sliceStream(current);
25904
- if (!current.next) {
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(current.start);
26637
+ tokenizer.defineSkip(current2.start);
25909
26638
  }
25910
- if (current._isInFirstContentOfListItem) {
26639
+ if (current2._isInFirstContentOfListItem) {
25911
26640
  tokenizer._gfmTasklistFirstContentOfListItem = true;
25912
26641
  }
25913
26642
  tokenizer.write(stream);
25914
- if (current._isInFirstContentOfListItem) {
26643
+ if (current2._isInFirstContentOfListItem) {
25915
26644
  tokenizer._gfmTasklistFirstContentOfListItem = void 0;
25916
26645
  }
25917
26646
  }
25918
- previous2 = current;
25919
- current = current.next;
26647
+ previous2 = current2;
26648
+ current2 = current2.next;
25920
26649
  }
25921
- current = token;
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
- current._tokenizer = void 0;
25930
- current.previous = void 0;
25931
- current = current.next;
26658
+ current2._tokenizer = void 0;
26659
+ current2.previous = void 0;
26660
+ current2 = current2.next;
25932
26661
  }
25933
26662
  }
25934
26663
  tokenizer.events = [];
25935
- if (current) {
25936
- current._tokenizer = void 0;
25937
- current.previous = void 0;
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(issueId, onUpdated);
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
- setDraftDescription(description);
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
- const success = await updateField("description", draftDescription.trim());
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
- ] }) : !readOnly ? /* @__PURE__ */ jsx(
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) => setDraftDescription(event.target.value),
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(Markdown, { components: markdownComponents, remarkPlugins: markdownRemarkPlugins, children: description }) }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-text-tertiary", children: "설명이 아직 없습니다." }),
35203
- error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-danger", children: error }) : null
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((current) => active ? "network" : current === "network" ? null : current);
37786
+ setActiveLogSection((current2) => active ? "network" : current2 === "network" ? null : current2);
36790
37787
  }, []);
36791
37788
  const handleConsoleDetailActiveChange = useCallback((active) => {
36792
- setActiveLogSection((current) => active ? "console" : current === "console" ? null : current);
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: ["issue", issueId, selectedProjectId],
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 current = node2;
37056
- for (let depth = 0; current && depth < HIDDEN_ANCESTOR_LIMIT; depth += 1) {
37057
- if (current.hasAttribute("hidden") || current.getAttribute("aria-hidden") === "true") {
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 (current.localName === "dialog" && !current.hasAttribute("open")) return false;
37061
- const style = view == null ? void 0 : view.getComputedStyle(current);
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 (current === node2 && (style == null ? void 0 : style.visibility) === "hidden") return false;
37064
- current = current.parentElement;
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((current) => current + 1);
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((current) => current + 1),
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
- showToast(hadVideo ? VIDEO_UPLOAD_COPY.created : "이슈가 생성되었습니다.");
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 current = buttons.indexOf(document.activeElement);
40831
+ const current2 = buttons.indexOf(document.activeElement);
39804
40832
  const delta = e.key === "ArrowRight" ? 1 : -1;
39805
- const next = (current + delta + buttons.length) % buttons.length;
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";