<script setup>
import { useNamespace, useLocale } from "@yh-ui/hooks";
import {
  ref,
  computed,
  watch,
  onBeforeUnmount,
  nextTick,
  shallowRef,
  onMounted,
  inject,
  useSlots
} from "vue";
import {
  aiArtifactsProps,
  aiArtifactsEmits
} from "./ai-artifacts";
import {
  createSandboxHtml,
  DEFAULT_SANDBOX_YH_UI_URL,
  DEFAULT_SANDBOX_YH_UI_CSS_URL
} from "./sandbox-renderer";
import { YhIcon } from "../../icon";
import { YhButton } from "../../button";
import { YhSpin } from "../../spin";
import { useComponentTheme } from "@yh-ui/theme";
import hljs, { loadHighlightStyle } from "../../highlight";
import { sanitizeHighlightedHtml } from "../../sanitize";
defineOptions({
  name: "YhAiArtifacts"
});
const props = defineProps(aiArtifactsProps);
const emit = defineEmits(aiArtifactsEmits);
const ns = useNamespace("ai-artifacts");
const { t } = useLocale();
const slots = useSlots();
const { themeStyle } = useComponentTheme(
  "ai-artifacts",
  computed(() => props.themeOverrides)
);
const internalMode = ref(props.mode);
const currentVersionState = ref(props.data?.currentVersion || "");
const isPreviewable = computed(() => {
  if (!props.data?.type) return false;
  const type = props.data.type;
  if (slots[type]) return true;
  const previewableTypes = [
    "html",
    "sandbox",
    "echarts",
    "chart",
    "canvas",
    "image",
    "video",
    "audio",
    "pdf",
    "iframe",
    "vue"
  ];
  return previewableTypes.includes(type);
});
const activeMode = computed(() => {
  if (internalMode.value === "preview" && !isPreviewable.value) {
    return "code";
  }
  return internalMode.value;
});
const escapeHtml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
const echartsRef = ref(null);
const echartsInstance = shallowRef(null);
const echartsLoading = ref(false);
const echartsError = ref(null);
let chartResizeObserver = null;
watch(
  () => props.mode,
  (val) => {
    internalMode.value = val;
  }
);
watch(
  () => props.data?.currentVersion,
  (val) => {
    if (val) currentVersionState.value = val;
  }
);
const getIcon = (type) => {
  if (type === "code") return "code";
  if (type === "chart" || type === "echarts") return "chart-bar";
  if (type === "canvas") return "edit";
  if (type === "sandbox") return "play";
  if (type === "diagram") return "connection";
  if (type === "image") return "image";
  if (type === "video") return "file-video";
  if (type === "audio") return "file-audio";
  if (type === "pdf") return "file-pdf";
  if (type === "text") return "document-text";
  if (type === "iframe") return "link";
  return "document";
};
const currentVersionData = computed(() => {
  if (!props.data || props.data.versions.length === 0) return null;
  return props.data.versions.find((v) => v.version === currentVersionState.value) || props.data.versions[0];
});
const getEchartsOption = computed(() => {
  if (props.data?.echartsOption) return props.data.echartsOption;
  return props.echartsOption;
});
const isEChartsContainer = computed(() => {
  if (props.data?.type === "echarts") return true;
  if (props.data?.type === "chart") {
    return !slots.chart && !!getEchartsOption.value;
  }
  return false;
});
const handleClose = () => {
  emit("update:visible", false);
  emit("close");
};
const toggleMode = (mode) => {
  internalMode.value = mode;
  emit("update:mode", mode);
};
const selectVersion = (v) => {
  currentVersionState.value = v.version;
  emit("version-change", v);
};
const sandboxSrcUrl = ref("");
const revokeCurrentUrl = () => {
  if (sandboxSrcUrl.value) {
    try {
      URL.revokeObjectURL(sandboxSrcUrl.value);
    } catch {
    }
    sandboxSrcUrl.value = "";
  }
};
watch(
  () => [props.visible, currentVersionData.value?.content, props.data?.type, activeMode.value],
  ([visible, content, type, mode]) => {
    revokeCurrentUrl();
    if (visible && content && (type === "html" || type === "sandbox") && (mode === "preview" || mode === "inline") && typeof window !== "undefined") {
      const blob = new Blob([content], { type: "text/html;charset=utf-8" });
      sandboxSrcUrl.value = URL.createObjectURL(blob);
    }
  },
  { immediate: true }
);
const highlightedCode = computed(() => {
  let content = currentVersionData.value?.content || "";
  const type = props.data?.type || "code";
  if (type === "echarts" && !content) {
    const opt = getEchartsOption.value;
    if (opt) {
      content = JSON.stringify(opt, null, 2);
    }
  }
  let lang = "typescript";
  if (type === "html") lang = "xml";
  if (type === "markdown") lang = "markdown";
  if (type === "react" || type === "vue") lang = "javascript";
  if (type === "echarts") lang = "json";
  if (lang && hljs.getLanguage(lang)) {
    try {
      return sanitizeHighlightedHtml(
        hljs.highlight(content, { language: lang, ignoreIllegals: true }).value
      );
    } catch {
      return sanitizeHighlightedHtml(escapeHtml(content));
    }
  }
  return sanitizeHighlightedHtml(hljs.highlightAuto(content).value);
});
const initECharts = async () => {
  const chartType = props.data?.type;
  if (chartType !== "chart" && chartType !== "echarts") return;
  const chartOption = getEchartsOption.value;
  if (!chartOption) return;
  echartsLoading.value = true;
  echartsError.value = null;
  try {
    if (chartResizeObserver) {
      chartResizeObserver.disconnect();
      chartResizeObserver = null;
    }
    if (echartsInstance.value) {
      echartsInstance.value.dispose();
      echartsInstance.value = null;
    }
    let echarts;
    if (props.autoLoadECharts) {
      echarts = await import("echarts");
    } else {
      echarts = window.echarts;
    }
    if (!echarts || !echartsRef.value) return;
    echartsInstance.value = echarts.init(echartsRef.value, chartOption.theme || props.echartsTheme);
    if (chartOption.option) {
      if (chartOption.dataZoom !== false && props.echartsDataZoom) {
        chartOption.option.dataZoom = chartOption.option.dataZoom || [
          { type: "inside" },
          { type: "slider" }
        ];
      }
      if (chartOption.toolbox !== false && props.echartsToolbox) {
        chartOption.option.toolbox = chartOption.option.toolbox || {
          feature: {
            dataZoom: { yAxisIndex: "none" },
            restore: {},
            saveAsImage: {}
          }
        };
      }
      echartsInstance.value.setOption(chartOption.option);
    }
    echartsInstance.value.on("click", (params) => {
      emit("chart-click", params);
    });
    emit("chart-ready", echartsInstance.value);
    if (props.responsiveWidth) {
      chartResizeObserver = new ResizeObserver(() => {
        echartsInstance.value?.resize();
      });
      chartResizeObserver.observe(echartsRef.value);
    }
  } catch (error) {
    echartsError.value = error;
    emit("chart-error", error);
  } finally {
    echartsLoading.value = false;
  }
};
watch(
  () => [props.visible, isEChartsContainer.value, getEchartsOption.value, activeMode.value],
  ([newVisible, isChart, , mode]) => {
    if (newVisible && isChart && (mode === "preview" || mode === "inline")) {
      nextTick(() => {
        initECharts();
      });
    }
  },
  { immediate: true }
);
const vueRendererIframeRef = ref(null);
const injectedYhUiUrl = inject("yhSandboxYhUiUrl", "");
const injectedYhUiCssUrl = inject("yhSandboxYhUiCssUrl", "");
const injectedRendererUrl = inject("yhSandboxRendererUrl", "");
const resolveRootUrl = (url) => {
  if (typeof window === "undefined" || !url.startsWith("/")) return url;
  const pathSegments = window.location.pathname.split("/");
  const baseIndex = pathSegments.indexOf("yh-ui");
  const subpath = baseIndex !== -1 ? "/" + pathSegments.slice(1, baseIndex + 1).join("/") : "";
  if (subpath && !url.startsWith(subpath)) {
    return `${window.location.origin}${subpath}${url.replace(/^\/+/, "")}`;
  }
  return `${window.location.origin}${url}`;
};
const resolvedSandboxYhUiUrl = computed(() => {
  const url = props.sandboxYhUiUrl || injectedYhUiUrl || DEFAULT_SANDBOX_YH_UI_URL;
  return resolveRootUrl(url);
});
const resolvedSandboxYhUiCssUrl = computed(() => {
  const url = props.sandboxYhUiCssUrl || injectedYhUiCssUrl || DEFAULT_SANDBOX_YH_UI_CSS_URL;
  return resolveRootUrl(url);
});
const vueRendererSrc = computed(() => {
  if (injectedRendererUrl) {
    const rendererUrl = resolveRootUrl(injectedRendererUrl);
    const params = new URLSearchParams({
      jsUrl: resolvedSandboxYhUiUrl.value,
      cssUrl: resolvedSandboxYhUiCssUrl.value
    });
    return `${rendererUrl}?${params.toString()}`;
  }
  return vueRendererBlobUrl.value;
});
const vueRendererBlobUrl = ref("");
const revokeSandboxBlobUrl = () => {
  if (vueRendererBlobUrl.value) {
    try {
      URL.revokeObjectURL(vueRendererBlobUrl.value);
    } catch {
    }
    vueRendererBlobUrl.value = "";
  }
};
const createVueSandbox = () => {
  if (typeof window === "undefined") return;
  if (injectedRendererUrl) return;
  revokeSandboxBlobUrl();
  const html = createSandboxHtml({
    yhUiUrl: resolvedSandboxYhUiUrl.value,
    yhUiCssUrl: resolvedSandboxYhUiCssUrl.value
  });
  const blob = new Blob([html], { type: "text/html;charset=utf-8" });
  vueRendererBlobUrl.value = URL.createObjectURL(blob);
};
watch([resolvedSandboxYhUiUrl, resolvedSandboxYhUiCssUrl], () => {
  if (typeof window !== "undefined" && !injectedRendererUrl) {
    createVueSandbox();
  }
});
const sendVueCodeToRenderer = () => {
  const iframe = vueRendererIframeRef.value;
  const content = currentVersionData.value?.content;
  if (iframe && iframe.contentWindow && content) {
    iframe.contentWindow.postMessage(
      {
        type: "render-vue",
        code: content
      },
      "*"
    );
  }
};
const onVueRendererLoad = () => {
  sendVueCodeToRenderer();
};
const handleRendererMessage = (event) => {
  if (event.data?.type === "renderer-ready") {
    sendVueCodeToRenderer();
  }
};
watch(
  () => currentVersionData.value?.content,
  () => {
    if (props.data?.type === "vue") {
      nextTick(() => {
        sendVueCodeToRenderer();
      });
    }
  }
);
onBeforeUnmount(() => {
  revokeCurrentUrl();
  revokeSandboxBlobUrl();
  if (chartResizeObserver) {
    chartResizeObserver.disconnect();
    chartResizeObserver = null;
  }
  if (echartsInstance.value) {
    echartsInstance.value.dispose();
    echartsInstance.value = null;
  }
  if (typeof window !== "undefined") {
    window.removeEventListener("message", handleRendererMessage);
  }
});
onMounted(() => {
  loadHighlightStyle();
  if (typeof window !== "undefined") {
    window.addEventListener("message", handleRendererMessage);
    createVueSandbox();
  }
});
const chartContainerStyle = computed(() => ({
  height: typeof props.chartHeight === "number" ? props.chartHeight + "px" : props.chartHeight
}));
</script>

<template>
  <Transition name="yh-slide-right">
    <div
      v-if="visible"
      :class="[ns.b(), ns.m(activeMode), ns.is('fullscreen', props.fullscreen)]"
      :style="[{
  width: props.fullscreen ? '100%' : typeof width === 'number' ? width + 'px' : width
}, themeStyle]"
    >
      <!-- Header -->
      <div :class="ns.e('header')">
        <div :class="ns.e('title-area')">
          <YhIcon :name="getIcon(data?.type)" />
          <span :class="ns.e('title')">{{ data?.title || "Artifact" }}</span>
        </div>

        <div :class="ns.e('actions')">
          <div v-if="isPreviewable" :class="ns.e('tabs')">
            <button
              :class="[ns.e('tab'), ns.is('active', activeMode === 'preview')]"
              @click="toggleMode('preview')"
            >
              {{ t("ai.artifacts.preview") }}
            </button>
            <button
              v-if="data?.type === 'html'"
              :class="[ns.e('tab'), ns.is('active', activeMode === 'inline')]"
              @click="toggleMode('inline')"
            >
              {{ t("ai.artifacts.inline") }}
            </button>
            <button
              :class="[ns.e('tab'), ns.is('active', activeMode === 'code')]"
              @click="toggleMode('code')"
            >
              {{ t("ai.artifacts.code") }}
            </button>
          </div>

          <YhButton text circle @click="handleClose">
            <template #icon>
              <YhIcon name="close" />
            </template>
          </YhButton>
        </div>
      </div>

      <!-- Version Bar -->
      <div v-if="data && data.versions.length > 1" :class="ns.e('version-bar')">
        <div :class="ns.e('version-label')">
          <YhIcon name="history" />
          <span>{{ t("ai.artifacts.versions") }}</span>
        </div>
        <div :class="ns.e('version-list')">
          <div
            v-for="v in data.versions"
            :key="v.version"
            :class="[ns.e('version-item'), ns.is('active', v.version === currentVersionState)]"
            @click="selectVersion(v)"
          >
            v{{ v.version }}
          </div>
        </div>
      </div>

      <!-- Content area -->
      <div :class="ns.e('content')">
        <template v-if="activeMode === 'preview' || activeMode === 'inline'">
          <!-- Check if a slot with the name of the type is defined, allowing custom preview rendering -->
          <template v-if="data?.type && slots[data.type]">
            <slot :name="data.type" :data="currentVersionData" :title="data.title" />
          </template>

          <template v-else>
            <iframe
              v-if="data?.type === 'html' || data?.type === 'sandbox'"
              :src="sandboxSrcUrl"
              :class="ns.e('sandbox')"
              :sandbox="data?.type === 'sandbox' ? 'allow-scripts' : ''"
            ></iframe>

            <!-- ECharts 图表 (使用 v-show 保持 DOM) -->
            <div
              v-show="isEChartsContainer"
              :class="ns.e('echarts-wrapper')"
              :style="chartContainerStyle"
              style="position: relative"
            >
              <div
                ref="echartsRef"
                :class="ns.e('echarts-container')"
                style="width: 100%; height: 100%"
              ></div>
              <YhSpin
                v-if="echartsLoading"
                :class="ns.e('chart-loading')"
                style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
              >
                <span>{{ chartLoadingText ?? t("ai.artifacts.renderingChart") }}</span>
              </YhSpin>
              <div
                v-else-if="echartsError"
                :class="ns.e('chart-error')"
                style="
                  position: absolute;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                  display: flex;
                  flex-direction: column;
                  align-items: center;
                "
              >
                <YhIcon name="warning" />
                <span
                  >{{
                    t("ai.artifacts.chartLoadError") === "ai.artifacts.chartLoadError" ? t("common.close") === "\u5173\u95ED" ? "\u56FE\u8868\u52A0\u8F7D\u5931\u8D25" : "Chart loading failed" : t("ai.artifacts.chartLoadError")
                  }}: {{ echartsError.message }}</span
                >
              </div>
            </div>

            <!-- 其他类型 -->
            <template
              v-if="data?.type !== 'html' && data?.type !== 'sandbox' && !isEChartsContainer"
            >
              <!-- Image Preview -->
              <div
                v-if="data?.type === 'image'"
                :class="ns.e('image-container')"
                style="
                  width: 100%;
                  height: 100%;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  overflow: auto;
                  padding: 16px;
                  box-sizing: border-box;
                "
              >
                <img
                  :src="currentVersionData?.content"
                  style="max-width: 100%; max-height: 100%; object-fit: contain"
                />
              </div>

              <!-- Video Preview -->
              <div
                v-else-if="data?.type === 'video'"
                :class="ns.e('video-container')"
                style="
                  width: 100%;
                  height: 100%;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  padding: 16px;
                  box-sizing: border-box;
                "
              >
                <video
                  :src="currentVersionData?.content"
                  controls
                  style="max-width: 100%; max-height: 100%"
                ></video>
              </div>

              <!-- Audio Preview -->
              <div
                v-else-if="data?.type === 'audio'"
                :class="ns.e('audio-container')"
                style="
                  width: 100%;
                  height: 100%;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  padding: 16px;
                  box-sizing: border-box;
                "
              >
                <audio :src="currentVersionData?.content" controls style="max-width: 100%"></audio>
              </div>

              <!-- PDF Preview -->
              <iframe
                v-else-if="data?.type === 'pdf'"
                :src="currentVersionData?.content"
                style="width: 100%; height: 100%; border: none"
              ></iframe>

              <!-- Plain Text Preview -->
              <pre
                v-else-if="data?.type === 'text'"
                style="
                  width: 100%;
                  height: 100%;
                  margin: 0;
                  padding: 16px;
                  overflow: auto;
                  font-family: monospace;
                  white-space: pre-wrap;
                  box-sizing: border-box;
                "
                >{{ currentVersionData?.content }}</pre
              >

              <!-- Generic Iframe Preview -->
              <iframe
                v-else-if="data?.type === 'iframe'"
                :src="currentVersionData?.content"
                style="width: 100%; height: 100%; border: none"
              ></iframe>

              <!-- Vue SFC Preview (Sandbox) -->
              <!-- Uses static vue-renderer.html when injected (avoids blob: COEP issue), -->
              <!-- otherwise falls back to a blob: URL for consumer apps. -->
              <iframe
                v-else-if="data?.type === 'vue' && vueRendererSrc"
                ref="vueRendererIframeRef"
                :src="vueRendererSrc"
                style="width: 100%; height: 100%; border: none"
                @load="onVueRendererLoad"
              ></iframe>

              <!-- 通用图表 -->
              <div
                v-else-if="data?.type === 'chart'"
                :class="ns.e('chart-container')"
                :style="chartContainerStyle"
              >
                <slot name="chart" :data="currentVersionData" :title="data.title">
                  <div :class="ns.e('placeholder')">
                    <YhIcon name="chart-bar" />
                    <p>{{ t("ai.artifacts.renderingChart") }}</p>
                  </div>
                </slot>
              </div>
              <!-- 画布 -->
              <div v-else-if="data?.type === 'canvas'" :class="ns.e('canvas-container')">
                <slot name="canvas" :data="currentVersionData">
                  <div :class="ns.e('placeholder')">
                    <YhIcon name="edit" />
                    <p>{{ t("ai.artifacts.renderingCanvas") }}</p>
                  </div>
                </slot>
              </div>
              <!-- 占位 -->
              <div v-else :class="ns.e('placeholder')">
                <YhIcon name="sparkles" />
                <p>{{ t("ai.artifacts.rendering") }}</p>
              </div>
            </template>
          </template>
        </template>

        <template v-else>
          <!-- eslint-disable-next-line vue/no-v-html -->
          <pre :class="ns.e('code-viewer')"><code v-html="highlightedCode"></code></pre>
        </template>
      </div>

      <!-- Footer Info -->
      <div :class="ns.e('footer')">
        <span v-if="currentVersionData?.timestamp">{{ currentVersionData.timestamp }}</span>
        <span v-if="currentVersionData?.description">{{ currentVersionData.description }}</span>
      </div>
    </div>
  </Transition>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-ai-artifacts {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  background: var(--yh-bg-color-overlay);
  border-left: 1px solid var(--yh-border-color-lighter);
  box-shadow: -10px 0 30px rgba(0, 0, 0, 0.1);
  display: flex;
  flex-direction: column;
  z-index: 1001;
  overflow: hidden;
  container-type: inline-size;
  container-name: ai-artifacts;
}
.yh-ai-artifacts.is-fullscreen {
  width: 100% !important;
  left: 0 !important;
  right: 0 !important;
}

.yh-ai-artifacts {
  /* Theme adjustments */
  background: var(--yh-ai-artifacts-bg-color, var(--yh-bg-color-overlay));
  /* Inline mode */
}
.yh-ai-artifacts--inline {
  position: relative;
  width: 100% !important;
  max-width: 100%;
  height: 400px;
  border: 1px solid var(--yh-border-color-lighter);
  border-radius: var(--yh-radius-md);
  margin: 12px 0;
  box-shadow: none;
}

html.dark .yh-ai-artifacts {
  background: var(--yh-ai-artifacts-bg-color, rgba(26, 26, 27, 0.9));
  backdrop-filter: blur(20px);
  border-left: 1px solid rgba(255, 255, 255, 0.08);
}
.yh-ai-artifacts__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--yh-border-color-lighter);
  background: var(--yh-bg-color-overlay);
}

.yh-ai-artifacts__title-area {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--yh-text-color-primary);
}
.yh-ai-artifacts__title-area .yh-icon {
  color: var(--yh-color-primary);
}

.yh-ai-artifacts__actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.yh-ai-artifacts__tabs {
  display: flex;
  background: var(--yh-fill-color-light);
  padding: 2px;
  border-radius: 8px;
}

.yh-ai-artifacts__tab {
  padding: 4px 12px;
  border: none;
  background: transparent;
  font-size: 13px;
  color: var(--yh-text-color-secondary);
  cursor: pointer;
  border-radius: 6px;
  transition: all 0.2s;
}
.yh-ai-artifacts__tab.is-active {
  background: var(--yh-bg-color-overlay);
  color: var(--yh-color-primary);
  box-shadow: var(--yh-shadow-sm);
}

.yh-ai-artifacts__version-bar {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  background: var(--yh-fill-color-lighter);
  border-bottom: 1px solid var(--yh-border-color-extra-light);
  gap: 12px;
}

.yh-ai-artifacts__version-label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--yh-text-color-placeholder);
  white-space: nowrap;
}

.yh-ai-artifacts__version-list {
  display: flex;
  gap: 6px;
  overflow-x: auto;
}
.yh-ai-artifacts__version-list::-webkit-scrollbar {
  display: none;
}

.yh-ai-artifacts__version-item {
  padding: 2px 8px;
  font-size: 12px;
  background: var(--yh-bg-color-overlay);
  border: 1px solid var(--yh-border-color-lighter);
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
}
.yh-ai-artifacts__version-item.is-active {
  background: var(--yh-color-primary-light-9);
  border-color: var(--yh-color-primary);
  color: var(--yh-color-primary);
}

.yh-ai-artifacts__content {
  flex: 1;
  overflow-x: hidden;
  overflow-y: auto;
  background: #fdfdfd;
  position: relative;
  display: flex;
  flex-direction: column;
}
html.dark .yh-ai-artifacts__content {
  background: #0d0d0d;
}

.yh-ai-artifacts__sandbox {
  width: 100%;
  height: 100%;
  border: none;
}

.yh-ai-artifacts__code-viewer {
  margin: 0;
  padding: 24px;
  height: 100%;
  overflow: auto;
  font-family: var(--yh-font-family-mono);
  font-size: 13px;
  line-height: 1.6;
  background: #282c34;
  color: #abb2bf;
}

.yh-ai-artifacts__placeholder {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--yh-text-color-secondary);
  gap: 16px;
}
.yh-ai-artifacts__placeholder .yh-icon {
  font-size: 48px;
  opacity: 0.2;
}

.yh-ai-artifacts__footer {
  padding: 8px 16px;
  font-size: 12px;
  color: var(--yh-text-color-placeholder);
  background: var(--yh-fill-color-light);
  display: flex;
  justify-content: space-between;
}

@container ai-artifacts (max-width: 720px) {
  .yh-ai-artifacts__header {
    flex-wrap: wrap;
    gap: 12px;
    align-items: flex-start;
  }
  .yh-ai-artifacts__actions {
    width: 100%;
    justify-content: space-between;
    flex-wrap: wrap;
  }
  .yh-ai-artifacts__tabs {
    flex: 1 1 auto;
    min-width: 0;
  }
}
@container ai-artifacts (max-width: 520px) {
  .yh-ai-artifacts__tab {
    flex: 1 1 0;
    text-align: center;
  }
  .yh-ai-artifacts__version-bar {
    flex-direction: column;
    align-items: flex-start;
  }
  .yh-ai-artifacts__footer {
    flex-direction: column;
    gap: 4px;
    align-items: flex-start;
  }
}

.yh-slide-right-enter-active,
.yh-slide-right-leave-active {
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.yh-slide-right-enter-from,
.yh-slide-right-leave-to {
  transform: translateX(100%);
}
</style>
