<template>
  <teleport to="body">
    <transition name="add-icon-fade" appear>
      <div
        v-if="open"
        class="add-icon-backdrop"
        @click.self="closeDialog"
      >
        <div class="add-icon-dialog" role="dialog" aria-modal="true" aria-label="添加图标">
          <aside class="add-icon-sidebar">
            <button
              class="sidebar-item"
              :class="{ active: activeTab === 'widgets' }"
              type="button"
              @click="setTab('widgets')"
            >
              <Icon class="sidebar-icon" icon="lucide:layout-grid" aria-hidden="true" />
              小组件
            </button>
            <button
              v-if="!isReplaceWidgetMode"
              class="sidebar-item"
              :class="{ active: activeTab === 'sites' }"
              type="button"
              @click="setTab('sites')"
            >
              <Icon class="sidebar-icon" icon="lucide:globe" aria-hidden="true" />
              网址导航
            </button>
            <button
              v-if="!isReplaceWidgetMode"
              class="sidebar-item"
              :class="{ active: activeTab === 'custom' }"
              type="button"
              @click="setTab('custom')"
            >
              <Icon class="sidebar-icon" icon="lucide:pencil" aria-hidden="true" />
              自定义图标
            </button>
          </aside>
          <div class="add-icon-content">
            <button class="dialog-close" type="button" @click="closeDialog">
              <Icon icon="lucide:x" aria-hidden="true" />
            </button>
            <div v-if="activeTab === 'custom'" class="custom-panel">
            <div class="form-row">
              <label>地址</label>
              <div class="input-group">
                <input
                  ref="urlInputRef"
                  v-model="url"
                  type="text"
                  placeholder="https://"
                />
                <button
                  class="ghost-button"
                  type="button"
                  :disabled="!url.trim()"
                  @click="fetchFavicon"
                >
                  获取图标
                </button>
              </div>
            </div>
            <div class="form-row">
              <label>名称</label>
              <input v-model="name" type="text" placeholder="网站名称" maxlength="16" />
            </div>
            <div class="form-row">
              <label>图标颜色</label>
              <div class="color-row">
                <button
                  v-for="item in colorOptions"
                  :key="item.id"
                  class="color-dot"
                  :class="{ selected: selectedColorId === item.id }"
                  type="button"
                  :style="item.previewStyle"
                  @click="selectColor(item)"
                ></button>
                <input
                  ref="colorInputRef"
                  v-model="customColor"
                  type="color"
                  class="color-input"
                  @input="updateCustomColor"
                />
              </div>
            </div>
            <div class="form-row">
              <label>图标文字</label>
              <input v-model="iconText" type="text" placeholder="A" maxlength="2" />
            </div>
            <div class="icon-type-row">
              <button
                class="icon-type-card"
                :class="{ active: iconType === 'text' }"
                type="button"
                @click="selectType('text')"
              >
                <div class="icon-preview" :style="{ backgroundColor: previewColor }">
                  <span>{{ previewText }}</span>
                </div>
                <span class="icon-type-label">文字图标</span>
              </button>
              <button
                class="icon-type-card"
                :class="{ active: iconType === 'image' }"
                type="button"
                @click="triggerUpload"
              >
                <div class="icon-preview image" :style="imagePreviewStyle">
                  <Icon v-if="!previewImage" icon="lucide:plus" aria-hidden="true" />
                </div>
                <span class="icon-type-label">上传</span>
              </button>
              <input
                ref="fileInputRef"
                class="file-input"
                type="file"
                accept="image/*"
                @change="handleFileChange"
              />
            </div>
            <div class="form-actions">
              <button
                class="btn btn-primary"
                type="button"
                :disabled="!canSubmit"
                @click="submit(false)"
              >
                保存
              </button>
              <button
                class="btn btn-secondary"
                type="button"
                :disabled="!canSubmit"
                @click="submit(true)"
              >
                保存并继续
              </button>
            </div>
            <div v-if="errorMessage" class="form-error">{{ errorMessage }}</div>
            </div>
            <div v-else class="list-panel">
              <div class="list-toolbar">
                <div class="search-input">
                  <Icon icon="lucide:search" aria-hidden="true" />
                  <input v-model="searchQuery" type="text" placeholder="输入并搜索" />
                </div>
                <button class="ghost-button small" type="button" @click="shuffleCurrent">
                  换一批
                </button>
              </div>
              <div class="category-row">
                <button
                  v-for="category in currentCategories"
                  :key="category"
                  class="category-chip"
                  :class="{ active: activeCategory === category }"
                  type="button"
                  @click="activeCategory = category"
                >
                  {{ category }}
                </button>
              </div>
              <div v-if="activeTab === 'widgets'" class="list-grid">
                <div
                  v-for="widget in filteredWidgets"
                  :key="widget.id"
                  class="list-card"
                >
                  <div class="list-card-header">
                    <div class="list-card-icon">
                      <Icon :icon="widget.icon" aria-hidden="true" />
                    </div>
                    <div>
                      <div class="list-card-title">{{ widget.name }}</div>
                      <div class="list-card-desc">{{ widget.description }}</div>
                    </div>
                  </div>
                  <div class="list-card-footer">
                    <span class="list-card-meta">{{ widget.size }}</span>
                    <button
                      class="card-add"
                      type="button"
                      @click="addWidget(widget)"
                    >
                      {{ isReplaceWidgetMode ? '替换' : '添加' }}
                    </button>
                  </div>
                </div>
              </div>
              <div v-else-if="activeTab === 'sites'" class="list-grid">
                <div
                  v-for="site in filteredSites"
                  :key="site.id"
                  class="list-card site-card"
                >
                  <div class="list-card-header">
                    <div
                      class="site-logo"
                      :style="{ backgroundImage: `url('${site.logo}')`, backgroundColor: site.color }"
                    ></div>
                    <div>
                      <div class="list-card-title">{{ site.name }}</div>
                      <div class="list-card-desc">{{ site.description }}</div>
                    </div>
                  </div>
                  <div class="list-card-footer">
                    <span class="list-card-meta">{{ site.meta }}</span>
                    <button
                      class="card-add"
                      type="button"
                      @click="addSite(site)"
                    >
                      添加
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </teleport>
</template>

<script setup lang="ts">
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { Icon } from '@iconify/vue';

type ColorOption = {
  id: string;
  value: string;
  previewStyle: Record<string, string>;
  isCustom?: boolean;
};

type WidgetSize = '1x1' | '1x2' | '2x1' | '2x2' | '2x4';

type WidgetOption = {
  id: string;
  name: string;
  description: string;
  icon: string;
  component: string;
  size: WidgetSize;
  category: string;
  data?: any;
};

type SiteOption = {
  id: string;
  name: string;
  description: string;
  url: string;
  logo: string;
  category: string;
  meta: string;
  color: string;
};

const props = defineProps<{
  open: boolean;
  mode?: 'add' | 'replace-widget';
  initialTab?: 'widgets' | 'sites' | 'custom';
  targetWidgetId?: string | null;
}>();

const emit = defineEmits<{
  (event: 'update:open', value: boolean): void;
  (event: 'submit', payload: { name: string; url: string; bgColor: string; img?: string; text?: string }): void;
  (event: 'add-widget', payload: { component: string; size?: WidgetSize; data?: any }): void;
  (event: 'replace-widget', payload: { id: string; component: string; size?: WidgetSize; data?: any }): void;
}>();

const colorOptions: ColorOption[] = [
  { id: 'blue', value: '#2f80ed', previewStyle: { backgroundColor: '#2f80ed' } },
  { id: 'orange', value: '#f2c94c', previewStyle: { backgroundColor: '#f2c94c' } },
  { id: 'red', value: '#eb5757', previewStyle: { backgroundColor: '#eb5757' } },
  { id: 'brown', value: '#4f4f4f', previewStyle: { backgroundColor: '#4f4f4f' } },
  { id: 'green', value: '#6fcf97', previewStyle: { backgroundColor: '#6fcf97' } },
  { id: 'navy', value: '#2d9cdb', previewStyle: { backgroundColor: '#2d9cdb' } },
  { id: 'gold', value: '#bb8f3e', previewStyle: { backgroundColor: '#bb8f3e' } },
  { id: 'plum', value: '#9b51e0', previewStyle: { backgroundColor: '#9b51e0' } },
  { id: 'rose', value: '#f15b5b', previewStyle: { backgroundColor: '#f15b5b' } },
  { id: 'blue-dark', value: '#2f5fd1', previewStyle: { backgroundColor: '#2f5fd1' } },
  { id: 'mint', value: '#8bd8bd', previewStyle: { backgroundColor: '#8bd8bd' } },
  { id: 'custom', value: '#7a7a7a', previewStyle: { backgroundImage: 'conic-gradient(#f66, #fa0, #6f6, #6cf, #66f, #c6f, #f66)' }, isCustom: true },
];

const widgetOptions: WidgetOption[] = [
  {
    id: 'calendar',
    name: '日历',
    description: '快速查看今天日期',
    icon: 'lucide:calendar',
    component: 'CalendarWidget',
    size: '1x1',
    category: '工具',
  },
  {
    id: 'hot-search',
    name: '热搜榜',
    description: '实时热门话题',
    icon: 'lucide:flame',
    component: 'HotSearchWidget',
    size: '2x1',
    category: '资讯',
    data: {
      tabs: ['微博', '抖音', '知乎'],
      items: [
        { title: '新品发布会', value: '78.9万' },
        { title: '节日出行攻略', value: '62.1万' },
        { title: '城市夜跑路线', value: '55.4万' },
        { title: '效率工具清单', value: '41.6万' },
      ],
    },
  },
  {
    id: 'countdown',
    name: '倒计时',
    description: '重要日程提醒',
    icon: 'lucide:timer',
    component: 'CountdownWidget',
    size: '2x1',
    category: '效率',
  },
];

const siteOptions: SiteOption[] = [
  {
    id: 'pdf',
    name: 'PDF转换大师',
    description: '在线转换与压缩',
    url: 'https://www.ilovepdf.com',
    logo: 'https://www.google.com/s2/favicons?domain=www.ilovepdf.com&sz=128',
    category: '效率',
    meta: '2604',
    color: '#2f80ed',
  },
  {
    id: 'video',
    name: '视频剪切',
    description: '剪辑、压缩、格式转换',
    url: 'https://www.clipchamp.com',
    logo: 'https://www.google.com/s2/favicons?domain=www.clipchamp.com&sz=128',
    category: '效率',
    meta: '4.73万',
    color: '#5b8cff',
  },
  {
    id: 'figma',
    name: 'Figma',
    description: '在线协作设计',
    url: 'https://www.figma.com',
    logo: 'https://www.google.com/s2/favicons?domain=www.figma.com&sz=128',
    category: '设计',
    meta: '1.9万',
    color: '#ff7262',
  },
  {
    id: 'github',
    name: 'GitHub',
    description: '代码托管与协作',
    url: 'https://github.com',
    logo: 'https://www.google.com/s2/favicons?domain=github.com&sz=128',
    category: '开发',
    meta: '3.4万',
    color: '#2f2f2f',
  },
  {
    id: 'notion',
    name: 'Notion',
    description: '笔记与知识管理',
    url: 'https://www.notion.so',
    logo: 'https://www.google.com/s2/favicons?domain=www.notion.so&sz=128',
    category: '工具',
    meta: '2.6万',
    color: '#d4b48d',
  },
  {
    id: 'bilibili',
    name: '哔哩哔哩',
    description: '视频与创作社区',
    url: 'https://www.bilibili.com',
    logo: 'https://www.google.com/s2/favicons?domain=www.bilibili.com&sz=128',
    category: '娱乐',
    meta: '9.2万',
    color: '#59c4f4',
  },
];

const widgetCategories = ['全部', '效率', '工具', '资讯'];
const siteCategories = ['全部', '效率', '工具', '开发', '设计', '创意', '娱乐', '其他'];

const url = ref('');
const name = ref('');
const iconText = ref('');
const selectedColorId = ref(colorOptions[0].id);
const customColor = ref('#8a8a8a');
const iconType = ref<'text' | 'image'>('text');
const fetchedImage = ref('');
const uploadedImage = ref('');
const errorMessage = ref('');
const fileInputRef = ref<HTMLInputElement | null>(null);
const colorInputRef = ref<HTMLInputElement | null>(null);
const urlInputRef = ref<HTMLInputElement | null>(null);
const activeTab = ref<'widgets' | 'sites' | 'custom'>('widgets');
const searchQuery = ref('');
const activeCategory = ref('全部');
const widgetOrder = ref(widgetOptions.map(item => item.id));
const siteOrder = ref(siteOptions.map(item => item.id));

const canSubmit = computed(() => name.value.trim().length > 0);
const previewText = computed(() => {
  const manual = iconText.value.trim();
  if (manual) return manual.slice(0, 2);
  const fallback = name.value.trim();
  return fallback ? fallback.charAt(0) : 'A';
});

const previewImage = computed(() => uploadedImage.value || fetchedImage.value);
const previewColor = computed(() => {
  const option = colorOptions.find(item => item.id === selectedColorId.value);
  if (option?.isCustom) return customColor.value;
  return option?.value ?? colorOptions[0].value;
});

const imagePreviewStyle = computed(() => ({
  backgroundImage: previewImage.value ? `url('${previewImage.value}')` : 'none',
}));

const dialogMode = computed(() => props.mode ?? 'add');
const isReplaceWidgetMode = computed(() => dialogMode.value === 'replace-widget');

const currentCategories = computed(() =>
  activeTab.value === 'widgets' ? widgetCategories : siteCategories
);

const orderedWidgets = computed(() => {
  const map = new Map(widgetOptions.map(item => [item.id, item]));
  return widgetOrder.value.map(id => map.get(id)).filter((item): item is WidgetOption => !!item);
});

const orderedSites = computed(() => {
  const map = new Map(siteOptions.map(item => [item.id, item]));
  return siteOrder.value.map(id => map.get(id)).filter((item): item is SiteOption => !!item);
});

const filteredWidgets = computed(() => {
  const query = searchQuery.value.trim().toLowerCase();
  return orderedWidgets.value.filter(item => {
    const matchCategory = activeCategory.value === '全部' || item.category === activeCategory.value;
    const matchQuery =
      !query ||
      item.name.toLowerCase().includes(query) ||
      item.description.toLowerCase().includes(query);
    return matchCategory && matchQuery;
  });
});

const filteredSites = computed(() => {
  const query = searchQuery.value.trim().toLowerCase();
  return orderedSites.value.filter(item => {
    const matchCategory = activeCategory.value === '全部' || item.category === activeCategory.value;
    const matchQuery =
      !query ||
      item.name.toLowerCase().includes(query) ||
      item.description.toLowerCase().includes(query);
    return matchCategory && matchQuery;
  });
});

const resetForm = () => {
  url.value = '';
  name.value = '';
  iconText.value = '';
  selectedColorId.value = colorOptions[0].id;
  customColor.value = '#8a8a8a';
  iconType.value = 'text';
  fetchedImage.value = '';
  uploadedImage.value = '';
  errorMessage.value = '';
};

const setTab = (tab: 'widgets' | 'sites' | 'custom') => {
  if (isReplaceWidgetMode.value && tab !== 'widgets') return;
  activeTab.value = tab;
  searchQuery.value = '';
  activeCategory.value = tab === 'widgets' ? widgetCategories[0] : siteCategories[0];
  if (tab === 'custom') {
    nextTick(() => urlInputRef.value?.focus());
  }
};

const shuffleCurrent = () => {
  if (activeTab.value === 'widgets') {
    widgetOrder.value = [...widgetOrder.value].sort(() => Math.random() - 0.5);
    return;
  }
  if (activeTab.value === 'sites') {
    siteOrder.value = [...siteOrder.value].sort(() => Math.random() - 0.5);
  }
};

const closeDialog = () => {
  emit('update:open', false);
};

const addWidget = (widget: WidgetOption) => {
  if (isReplaceWidgetMode.value) {
    if (!props.targetWidgetId) return;
    emit('replace-widget', {
      id: props.targetWidgetId,
      component: widget.component,
      size: widget.size,
      data: widget.data,
    });
    closeDialog();
    return;
  }
  emit('add-widget', {
    component: widget.component,
    size: widget.size,
    data: widget.data,
  });
};

const addSite = (site: SiteOption) => {
  emit('submit', {
    name: site.name,
    url: normalizeUrl(site.url),
    bgColor: site.color,
    img: site.logo,
  });
};

const selectColor = (item: ColorOption) => {
  selectedColorId.value = item.id;
  if (item.isCustom && colorInputRef.value) {
    colorInputRef.value.click();
  }
};

const updateCustomColor = () => {
  selectedColorId.value = 'custom';
};

const selectType = (type: 'text' | 'image') => {
  iconType.value = type;
};

const triggerUpload = () => {
  iconType.value = 'image';
  fileInputRef.value?.click();
};

const handleFileChange = (event: Event) => {
  const input = event.target as HTMLInputElement | null;
  const file = input?.files?.[0];
  if (!file) return;
  const reader = new FileReader();
  reader.onload = () => {
    uploadedImage.value = String(reader.result);
    iconType.value = 'image';
  };
  reader.readAsDataURL(file);
};

const normalizeUrl = (value: string) => {
  if (!value.trim()) return '#';
  try {
    return new URL(value).toString();
  } catch {
    try {
      return new URL(`https://${value}`).toString();
    } catch {
      return '#';
    }
  }
};

const fetchFavicon = () => {
  errorMessage.value = '';
  const raw = url.value.trim();
  if (!raw) return;
  const resolved = normalizeUrl(raw);
  if (resolved === '#') {
    errorMessage.value = '请输入有效的网址';
    return;
  }
  const parsed = new URL(resolved);
  const favicon = `https://www.google.com/s2/favicons?domain=${parsed.hostname}&sz=128`;
  fetchedImage.value = favicon;
  iconType.value = 'image';
  if (!name.value.trim()) {
    name.value = parsed.hostname.replace(/^www\./, '');
  }
};

const submit = (keepOpen: boolean) => {
  if (!canSubmit.value) return;
  const iconPayload = {
    name: name.value.trim(),
    url: normalizeUrl(url.value.trim()),
    bgColor: previewColor.value,
    img: iconType.value === 'image' && previewImage.value ? previewImage.value : undefined,
    text: iconType.value === 'text' ? iconText.value.trim() || previewText.value : undefined,
  };
  emit('submit', iconPayload);
  if (keepOpen) {
    resetForm();
    nextTick(() => {
      fileInputRef.value?.value && (fileInputRef.value.value = '');
    });
  } else {
    closeDialog();
  }
};

const handleKeydown = (event: KeyboardEvent) => {
  if (!props.open) return;
  if (event.key === 'Escape') {
    event.preventDefault();
    closeDialog();
  }
};

onMounted(() => {
  window.addEventListener('keydown', handleKeydown);
});

onBeforeUnmount(() => {
  window.removeEventListener('keydown', handleKeydown);
});

watch(
  () => props.open,
  value => {
    if (value) {
      resetForm();
      setTab(props.initialTab ?? 'widgets');
      nextTick(() => urlInputRef.value?.focus());
    }
  }
);
</script>

<style lang="scss" scoped>
@import '@/styles/tokens.scss';

.add-icon-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: $z-index-modal;
}

.add-icon-dialog {
  width: min(920px, 92vw);
  height: min(560px, 90vh);
  display: grid;
  grid-template-columns: 180px 1fr;
  gap: 0;
  border-radius: $border-radius-large;
  background: rgba(24, 24, 24, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: $shadow-lg;
  overflow: hidden;
  backdrop-filter: blur($backdrop-filter-blur) saturate($backdrop-filter-saturation);
  position: relative;
}

.add-icon-sidebar {
  padding: 24px 16px;
  background: rgba(0, 0, 0, 0.2);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.sidebar-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: $border-radius-medium;
  color: $color-text-secondary;
  font-size: 14px;
  background: transparent;
  border: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  transition: background-color $motion-duration-sm $motion-easing-standard,
    color $motion-duration-sm $motion-easing-standard;
}

.sidebar-item:hover {
  background: rgba(255, 255, 255, 0.06);
  color: $color-text-primary;
}

.sidebar-item.active {
  background: rgba(255, 255, 255, 0.08);
  color: $color-text-primary;
  position: relative;
}

.sidebar-item.active::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: 3px;
  height: 20px;
  transform: translateY(-50%);
  border-radius: 2px;
  background: $color-accent;
}

.sidebar-icon {
  width: 16px;
  height: 16px;
}

.add-icon-content {
  padding: 36px 48px 32px 32px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  position: relative;
  overflow: hidden;
  height: 100%;
  min-height: 0;
}

.dialog-close {
  position: absolute;
  right: 18px;
  top: 16px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: $color-text-primary;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.form-row {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 12px;
  align-items: center;
  font-size: 13px;
  color: $color-text-secondary;
}

.form-row input {
  height: 34px;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.08);
  color: $color-text-primary;
  padding: 0 12px;
  outline: none;
}

.input-group {
  display: flex;
  gap: 12px;
}

.input-group input {
  flex: 1;
}

.ghost-button {
  padding: 6px 14px;
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: transparent;
  color: $color-text-primary;
  cursor: pointer;
}

.ghost-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.color-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.color-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
}

.color-dot.selected {
  border-color: #fff;
}

.color-input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.icon-type-row {
  display: flex;
  gap: 14px;
  align-items: flex-end;
}

.icon-type-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  background: transparent;
  border: none;
  color: $color-text-secondary;
  cursor: pointer;
}

.icon-type-card.active {
  color: $color-text-primary;
}

.icon-preview {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.14);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 20px;
  font-weight: 600;
  box-shadow: $shadow-sm;
  background-size: cover;
  background-position: center;
}

.icon-preview.image {
  background-color: rgba(255, 255, 255, 0.08);
}

.icon-type-label {
  font-size: 12px;
}

.file-input {
  display: none;
}

.form-actions {
  display: flex;
  gap: 12px;
  margin-top: 6px;
}

.btn {
  padding: 8px 18px;
  border-radius: 16px;
  border: none;
  font-size: 13px;
  cursor: pointer;
}

.btn-primary {
  background: #1e88ff;
  color: #fff;
}

.btn-secondary {
  background: rgba(255, 255, 255, 0.12);
  color: $color-text-primary;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.form-error {
  color: #ff8181;
  font-size: 12px;
}

.custom-panel {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.list-panel {
  display: flex;
  flex-direction: column;
  gap: 14px;
  height: 100%;
  min-height: 0;
}

.list-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.search-input {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.08);
  color: $color-text-secondary;
  font-size: 13px;
}

.search-input input {
  flex: 1;
  border: none;
  background: transparent;
  color: $color-text-primary;
  outline: none;
  font-size: 13px;
}

.ghost-button.small {
  padding: 6px 12px;
  font-size: 12px;
}

.category-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.category-chip {
  padding: 4px 10px;
  border-radius: 999px;
  border: none;
  background: rgba(255, 255, 255, 0.08);
  color: $color-text-secondary;
  font-size: 12px;
  cursor: pointer;
}

.category-chip.active {
  background: rgba(30, 136, 255, 0.28);
  color: $color-text-primary;
}

.list-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  overflow: auto;
  padding-right: 4px;
  flex: 1;
}

.list-card {
  background: rgba(255, 255, 255, 0.08);
  border-radius: 16px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 150px;
}

.list-card-header {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.list-card-icon,
.site-logo {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
  color: $color-text-primary;
  background-size: cover;
  background-position: center;
}

.site-logo {
  background-size: 60%;
  background-repeat: no-repeat;
}

.list-card-icon svg {
  width: 22px;
  height: 22px;
}

.list-card-title {
  font-size: 14px;
  font-weight: 600;
  color: $color-text-primary;
}

.list-card-desc {
  margin-top: 4px;
  font-size: 12px;
  color: $color-text-secondary;
}

.list-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: auto;
}

.list-card-meta {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.6);
  display: flex;
  align-items: center;
  gap: 6px;
}

.site-card .list-card-meta::before {
  content: '🔥';
  font-size: 12px;
}

.card-add {
  padding: 4px 12px;
  border-radius: 12px;
  border: none;
  background: #1e88ff;
  color: #fff;
  font-size: 12px;
  cursor: pointer;
}

.card-add:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (max-width: 720px) {
  .list-grid {
    grid-template-columns: 1fr;
  }
}

.add-icon-fade-enter-active,
.add-icon-fade-leave-active {
  transition: opacity 220ms ease;
}

.add-icon-fade-enter-from,
.add-icon-fade-leave-to {
  opacity: 0;
}

.add-icon-fade-enter-active .add-icon-dialog,
.add-icon-fade-leave-active .add-icon-dialog {
  transition: transform 240ms ease, opacity 240ms ease;
}

.add-icon-fade-enter-from .add-icon-dialog,
.add-icon-fade-leave-to .add-icon-dialog {
  transform: translateY(6px) scale(0.98);
  opacity: 0;
}

@media (max-width: 860px) {
  .add-icon-dialog {
    grid-template-columns: 1fr;
  }

  .add-icon-sidebar {
    flex-direction: row;
    justify-content: space-around;
  }
}
</style>
