<template>
  <main class="container page-padding">

    <VAlert v-if="error" type="error" :message="error" class="mb-3" :closable="false">
      <template #actions>
        <VButton variant="danger" size="sm" @click="fetchListsAndGroups">{{ t('listsPage.retryButton') }}</VButton>
      </template>
    </VAlert>

    <VCard v-else-if="filteredLists.length === 0 && !loading" variant="empty-state" empty-icon="clipboard"
      :empty-title="t(noListsMessageKey)">
      <template #default>
        <p v-if="!currentGroupId">{{ t('listsPage.emptyState.personalGlobalInfo') }}</p>
        <p v-else>{{ t('listsPage.emptyState.groupSpecificInfo') }}</p>
      </template>
      <template #empty-actions>
        <VButton variant="primary" class="mt-2" @click="showCreateModal = true" icon-left="plus">
          {{ t('listsPage.createNewListButton') }}
        </VButton>
      </template>
    </VCard>

    <div v-else-if="loading && filteredLists.length === 0" class="loading-placeholder">
      {{ t('listsPage.loadingLists') }}
    </div>

    <div v-else>
      <div class="neo-lists-grid">
        <div v-for="list in filteredLists" :key="list.id" class="neo-list-card"
          :class="{ 'touch-active': touchActiveListId === list.id, 'archived': list.archived_at }"
          @click="navigateToList(list.id)" @touchstart.passive="handleTouchStart(list.id)"
          @touchend.passive="handleTouchEnd" @touchcancel.passive="handleTouchEnd" :data-list-id="list.id">
          <div class="neo-list-header">
            <span>{{ list.name }}</span>
            <!-- <div class="actions">
              <VButton v-if="!list.archived_at" @click.stop="archiveList(list)" variant="danger" size="sm"
                icon="archive" />
              <VButton v-else @click.stop="unarchiveList(list)" variant="success" size="sm" icon="unarchive" />
            </div> -->
          </div>
          <div class="neo-list-desc">{{ list.description || t('listsPage.noDescription') }}</div>
          <ul class="neo-item-list">
            <li v-for="item in list.items" :key="item.id || item.tempId" class="neo-list-item" :data-item-id="item.id"
              :data-item-temp-id="item.tempId" :class="{ 'is-updating': item.updating }">
              <label class="neo-checkbox-label" @click.stop>
                <input type="checkbox" :checked="item.is_complete" @change="toggleItem(list, item)"
                  :disabled="item.id === undefined && item.tempId !== undefined" />
                <div class="checkbox-content">
                  <span class="checkbox-text-span"
                    :class="{ 'neo-completed-static': item.is_complete && !item.updating }">{{
                      item.name }}</span>
                </div>
              </label>
            </li>
            <li v-if="!list.archived_at" class="neo-list-item new-item-input-container">
              <label class="neo-checkbox-label">
                <input type="checkbox" disabled />
                <input type="text" class="neo-new-item-input" :placeholder="t('listsPage.addItemPlaceholder')"
                  ref="newItemInputRefs" :data-list-id="list.id" @keyup.enter="addNewItem(list, $event)"
                  @blur="handleNewItemBlur(list, $event)" @click.stop />
              </label>
            </li>
          </ul>
        </div>
        <div class="neo-create-list-card" @click="showCreateModal = true" ref="createListCardRef">
          {{ t('listsPage.createCard.title') }}
        </div>
      </div>
    </div>

    <CreateListModal v-model="showCreateModal" :groups="availableGroupsForModal" @created="onListCreated" />
  </main>
</template>

<script setup lang="ts">
import { ref, onMounted, computed, watch, onUnmounted, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { apiClient, API_ENDPOINTS } from '@/services/api';
import CreateListModal from '@/components/CreateListModal.vue';
import { useStorage } from '@vueuse/core';
import VAlert from '@/components/valerie/VAlert.vue';
import VCard from '@/components/valerie/VCard.vue';
import VButton from '@/components/valerie/VButton.vue';
import VToggleSwitch from '@/components/valerie/VToggleSwitch.vue';

const { t } = useI18n();

interface ListStatus {
  id: number;
  updated_at: string;
  item_count: number;
  latest_item_updated_at: string | null;
}

interface List {
  id: number;
  name: string;
  description?: string;
  is_complete: boolean;
  updated_at: string;
  created_by_id: number;
  group_id?: number | null;
  created_at: string;
  version: number;
  items: Item[];
  archived_at?: string | null;
}

interface Group {
  id: number;
  name: string;
}

interface Item {
  id: number | string;
  tempId?: string;
  name: string;
  quantity?: string | number;
  is_complete: boolean;
  price?: number | null;
  version: number;
  updating?: boolean;
  created_at?: string;
  updated_at: string;
}

const props = defineProps<{
  groupId?: number | string;
}>();

const route = useRoute();
const router = useRouter();

const loading = ref(true);
const error = ref<string | null>(null);
const lists = ref<(List & { items: Item[] })[]>([]);
const archivedLists = ref<List[]>([]);
const haveFetchedArchived = ref(false);
const allFetchedGroups = ref<Group[]>([]);
const currentViewedGroup = ref<Group | null>(null);
const showCreateModal = ref(false);
const newItemInputRefs = ref<HTMLInputElement[]>([]);

const pollingInterval = ref<ReturnType<typeof setInterval> | null>(null);

const currentGroupId = computed<number | null>(() => {
  const idFromProp = props.groupId;
  const idFromRoute = route.params.groupId;
  if (idFromProp) {
    return typeof idFromProp === 'string' ? parseInt(idFromProp, 10) : idFromProp;
  }
  if (idFromRoute) {
    return parseInt(idFromRoute as string, 10);
  }
  return null;
});

const fetchCurrentViewGroupName = async () => {
  if (!currentGroupId.value) {
    currentViewedGroup.value = null;
    return;
  }
  const found = allFetchedGroups.value.find(g => g.id === currentGroupId.value);
  if (found) {
    currentViewedGroup.value = found;
    return;
  }
  try {
    const response = await apiClient.get(API_ENDPOINTS.GROUPS.BY_ID(String(currentGroupId.value)));
    currentViewedGroup.value = response.data as Group;
  } catch (err) {
    console.error(`Failed to fetch group name for ID ${currentGroupId.value}:`, err);
    currentViewedGroup.value = null;
  }
};

const pageTitle = computed(() => {
  if (currentGroupId.value) {
    return currentViewedGroup.value
      ? t('listsPage.pageTitle.forGroup', { groupName: currentViewedGroup.value.name })
      : t('listsPage.pageTitle.forGroupId', { groupId: currentGroupId.value });
  }
  return t('listsPage.pageTitle.myLists');
});

const noListsMessageKey = computed(() => {
  if (currentGroupId.value) {
    return 'listsPage.emptyState.noListsForGroup';
  }
  return 'listsPage.emptyState.noListsYet';
});

const fetchAllAccessibleGroups = async () => {
  try {
    const response = await apiClient.get(API_ENDPOINTS.GROUPS.BASE);
    allFetchedGroups.value = (response.data as Group[]);
  } catch (err) {
    console.error('Failed to fetch groups for modal:', err);
  }
};

const cachedLists = useStorage<(List & { items: Item[] })[]>('cached-lists', []);
const cachedTimestamp = useStorage<number>('cached-lists-timestamp', 0);
const CACHE_DURATION = 5 * 60 * 1000;

const loadCachedData = () => {
  const now = Date.now();
  if (cachedLists.value.length > 0 && (now - cachedTimestamp.value) < CACHE_DURATION) {
    lists.value = JSON.parse(JSON.stringify(cachedLists.value));
    loading.value = false;
  }
};

const fetchLists = async () => {
  error.value = null;

  // Only show loading if we don't have any cached data to display
  if (lists.value.length === 0) {
    loading.value = true;
  }

  try {
    const endpoint = currentGroupId.value
      ? API_ENDPOINTS.GROUPS.LISTS(String(currentGroupId.value))
      : API_ENDPOINTS.LISTS.BASE;
    const response = await apiClient.get(endpoint);
    lists.value = (response.data as (List & { items: Item[] })[]).map(list => ({
      ...list,
      items: list.items || []
    }));
    cachedLists.value = JSON.parse(JSON.stringify(lists.value));
    cachedTimestamp.value = Date.now();
  } catch (err: unknown) {
    error.value = err instanceof Error ? err.message : t('listsPage.errors.fetchFailed');
    console.error(error.value, err);
    // If we have cached data and there's an error, don't clear the lists
    if (cachedLists.value.length === 0) lists.value = [];
  } finally {
    loading.value = false;
  }
};

const fetchArchivedLists = async () => {
  if (haveFetchedArchived.value) return;
  try {
    const endpoint = API_ENDPOINTS.LISTS.ARCHIVED;
    const response = await apiClient.get(endpoint);
    archivedLists.value = response.data as List[];
    haveFetchedArchived.value = true;
  } catch (err) {
    console.error('Failed to fetch archived lists:', err);
  }
};

const fetchListsAndGroups = async () => {
  // Only show loading if we don't have cached data
  if (lists.value.length === 0) {
    loading.value = true;
  }

  try {
    await Promise.all([
      fetchLists(),
      fetchAllAccessibleGroups()
    ]);
    await fetchCurrentViewGroupName();
  } catch (err) {
    console.error('Error in fetchListsAndGroups:', err);
  } finally {
    loading.value = false;
  }
};

const availableGroupsForModal = computed(() => {
  return allFetchedGroups.value.map(group => ({
    label: group.name,
    value: group.id,
  }));
});

const getGroupName = (groupId?: number | null): string | undefined => {
  if (!groupId) return undefined;
  return allFetchedGroups.value.find(g => g.id === groupId)?.name;
}

const onListCreated = (newList: List & { items: Item[] }) => {
  lists.value.push({
    ...newList,
    items: newList.items || []
  });
  cachedLists.value = JSON.parse(JSON.stringify(lists.value));
  cachedTimestamp.value = Date.now();
};

const toggleItem = async (list: List, item: Item) => {
  if (typeof item.id === 'string' && item.id.startsWith('temp-')) {
    return;
  }
  const originalIsComplete = item.is_complete;
  item.is_complete = !item.is_complete;
  item.updating = true;

  try {
    await apiClient.put(
      API_ENDPOINTS.LISTS.ITEM(String(list.id), String(item.id)),
      {
        is_complete: item.is_complete,
        version: item.version,
        name: item.name,
        quantity: item.quantity,
        price: item.price
      }
    );
    item.version++;
  } catch (err) {
    item.is_complete = originalIsComplete;
    console.error('Failed to update item:', err);
    const itemElement = document.querySelector(`.neo-list-item[data-item-id="${item.id}"]`);
    if (itemElement) {
      itemElement.classList.add('error-flash');
      setTimeout(() => itemElement.classList.remove('error-flash'), 800);
    }
  } finally {
    item.updating = false;
  }
};

const addNewItem = async (list: List, event: Event) => {
  const inputElement = event.target as HTMLInputElement;
  const itemName = inputElement.value.trim();

  if (!itemName) {
    if (event.type === 'blur') inputElement.value = '';
    return;
  }

  const localTempId = `temp-${Date.now()}`;
  const newItem: Item = {
    id: localTempId,
    tempId: localTempId,
    name: itemName,
    is_complete: false,
    version: 0,
    updating: true,
    created_at: new Date().toISOString(),
    updated_at: new Date().toISOString(),
  };

  list.items.push(newItem);
  const originalInputValue = inputElement.value;
  inputElement.value = '';
  inputElement.disabled = true;

  await nextTick();

  const newItemLiElement = document.querySelector(`.neo-list-item[data-item-temp-id="${localTempId}"]`);
  if (newItemLiElement) {
    newItemLiElement.classList.add('item-appear');
  }

  try {
    const response = await apiClient.post(API_ENDPOINTS.LISTS.ITEMS(String(list.id)), {
      name: itemName,
      is_complete: false,
    });
    const addedItemFromServer = response.data as Item;

    const itemIndex = list.items.findIndex(i => i.tempId === localTempId);
    if (itemIndex !== -1) {
      list.items.splice(itemIndex, 1, {
        ...newItem,
        ...addedItemFromServer,
        updating: false,
        tempId: undefined
      });
    }
    if (event.type === 'keyup' && (event as KeyboardEvent).key === 'Enter') {
      inputElement.disabled = false;
      inputElement.focus();
    } else {
      inputElement.disabled = false;
    }
  } catch (err) {
    console.error('Failed to add new item:', err);
    list.items = list.items.filter(i => i.tempId !== localTempId);
    inputElement.value = originalInputValue;
    inputElement.disabled = false;
    inputElement.style.transition = 'border-color 0.5s ease';
    inputElement.style.borderColor = 'red';
    setTimeout(() => {
      inputElement.style.borderColor = '#ccc';
    }, 500);
  }
};

const handleNewItemBlur = (list: List, event: Event) => {
  const inputElement = event.target as HTMLInputElement;
  if (inputElement.value.trim()) {
    addNewItem(list, event);
  }
};

const navigateToList = (listId: number) => {
  const selectedList = lists.value.find(l => l.id === listId);
  if (selectedList) {
    const listShell = {
      id: selectedList.id,
      name: selectedList.name,
      description: selectedList.description,
      group_id: selectedList.group_id,
    };
    sessionStorage.setItem('listDetailShell', JSON.stringify(listShell));
  }
  router.push({ name: 'ListDetail', params: { id: listId } });
};

const prefetchListDetails = async (listId: number) => {
  try {
    const response = await apiClient.get(API_ENDPOINTS.LISTS.BY_ID(String(listId)));
    const fullListData = response.data;
    sessionStorage.setItem(`listDetailFull_${listId}`, JSON.stringify(fullListData));
  } catch (err) {
    console.warn('Pre-fetch failed:', err);
  }
};

let intersectionObserver: IntersectionObserver | null = null;
const setupIntersectionObserver = () => {
  if (intersectionObserver) intersectionObserver.disconnect();

  intersectionObserver = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const listId = entry.target.getAttribute('data-list-id');
        if (listId) {
          const cachedFullData = sessionStorage.getItem(`listDetailFull_${listId}`);
          if (!cachedFullData) {
            prefetchListDetails(Number(listId));
          }
        }
      }
    });
  }, {
    rootMargin: '100px 0px',
    threshold: 0.01
  });

  nextTick(() => {
    document.querySelectorAll('.neo-list-card[data-list-id]').forEach(card => {
      intersectionObserver!.observe(card);
    });
  });
};

const touchActiveListId = ref<number | null>(null);
const handleTouchStart = (listId: number) => { touchActiveListId.value = listId; };
const handleTouchEnd = () => { touchActiveListId.value = null; };

const refetchList = async (listId: number) => {
  try {
    const response = await apiClient.get(API_ENDPOINTS.LISTS.BY_ID(String(listId)));
    const updatedList = response.data as List;
    const listIndex = lists.value.findIndex(l => l.id === listId);

    if (listIndex !== -1) {
      lists.value[listIndex] = { ...updatedList, items: updatedList.items || [] };
      cachedLists.value = JSON.parse(JSON.stringify(lists.value));
      cachedTimestamp.value = Date.now();
    } else {
    }
  } catch (err) {
    console.error(`Failed to refetch list ${listId}:`, err);
  }
};

const checkForUpdates = async () => {
  if (lists.value.length === 0) {
    return;
  }

  const listIds = lists.value.map(l => l.id);
  if (listIds.length === 0) return;

  try {
    const response = await apiClient.get(API_ENDPOINTS.LISTS.STATUSES, {
      params: { ids: listIds }
    });
    const statuses = response.data as ListStatus[];

    for (const status of statuses) {
      const localList = lists.value.find(l => l.id === status.id);
      if (localList) {
        const localUpdatedAt = new Date(localList.updated_at).getTime();
        const remoteUpdatedAt = new Date(status.updated_at).getTime();
        const localItemCount = localList.items.length;
        const remoteItemCount = status.item_count;

        const localLatestItemUpdate = localList.items.reduce((latest, item) => {
          const itemDate = new Date(item.updated_at).getTime();
          return itemDate > latest ? itemDate : latest;
        }, 0);

        const remoteLatestItemUpdate = status.latest_item_updated_at
          ? new Date(status.latest_item_updated_at).getTime()
          : 0;

        if (
          remoteUpdatedAt > localUpdatedAt ||
          localItemCount !== remoteItemCount ||
          (remoteLatestItemUpdate > localLatestItemUpdate)
        ) {
          await refetchList(status.id);
        }
      }
    }
  } catch (err) {
    console.warn('Polling for list updates failed:', err);
  }
};

const startPolling = () => {
  stopPolling();
  pollingInterval.value = setInterval(checkForUpdates, 15000);
};

const stopPolling = () => {
  if (pollingInterval.value) {
    clearInterval(pollingInterval.value);
    pollingInterval.value = null;
  }
};

const showArchived = ref(false);

watch(showArchived, (isShowing) => {
  if (isShowing) {
    fetchArchivedLists();
  }
});

const filteredLists = computed(() => {
  if (showArchived.value) {
    const combined = [...lists.value, ...archivedLists.value];
    const uniqueLists = Array.from(new Map(combined.map(l => [l.id, l])).values());
    return uniqueLists.sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime());
  }
  return lists.value.filter(list => !list.archived_at);
});

const archiveList = async (list: List) => {
  try {
    await apiClient.delete(API_ENDPOINTS.LISTS.BY_ID(list.id.toString()));
    list.archived_at = new Date().toISOString();
    const listIndex = lists.value.findIndex(l => l.id === list.id);
    if (listIndex > -1) {
      const [archivedItem] = lists.value.splice(listIndex, 1);
      archivedLists.value.push(archivedItem);
    }
  } catch (error) {
    console.error('Failed to archive list', error);
  }
};

const unarchiveList = async (list: List) => {
  try {
    const response = await apiClient.post(API_ENDPOINTS.LISTS.UNARCHIVE(list.id.toString()));
    const unarchivedList = response.data as List;

    const listIndex = archivedLists.value.findIndex(l => l.id === list.id);
    if (listIndex > -1) {
      archivedLists.value.splice(listIndex, 1);
    }

    lists.value.push({ ...unarchivedList, items: unarchivedList.items || [] });

  } catch (error) {
    console.error('Failed to unarchive list', error);
  }
};

onMounted(() => {
  loadCachedData();
  fetchListsAndGroups().then(() => {
    if (lists.value.length > 0) {
      setupIntersectionObserver();
      startPolling();
    }
  });
});

watch(currentGroupId, () => {
  loadCachedData();
  haveFetchedArchived.value = false;
  archivedLists.value = [];
  fetchListsAndGroups().then(() => {
    if (lists.value.length > 0) {
      setupIntersectionObserver();
      startPolling();
    } else {
      stopPolling();
    }
  });
});

watch(() => lists.value.length, (newLength, oldLength) => {
  if (newLength > 0 && oldLength === 0 && !loading.value) {
    setupIntersectionObserver();
  }
  if (newLength > 0) {
    startPolling();
    nextTick(() => {
      document.querySelectorAll('.neo-list-card[data-list-id]').forEach(card => {
        if (intersectionObserver) {
          intersectionObserver.observe(card);
        }
      });
    });
  }
});

onUnmounted(() => {
  if (intersectionObserver) {
    intersectionObserver.disconnect();
  }
  stopPolling();
});

</script>

<style scoped>
.loading-placeholder {
  text-align: center;
  padding: 2rem;
  font-size: 1.2rem;
  color: #555;
}

.page-padding {
  padding: 1rem;
  max-width: 1600px;
  margin: 0 auto;
}

.mb-3 {
  margin-bottom: 1.5rem;
}

.neo-lists-grid {
  columns: 3 500px;
  column-gap: 2rem;
  margin-bottom: 2rem;
}

.neo-list-card,
.neo-create-list-card {
  break-inside: avoid;
  border-radius: 18px;
  box-shadow: 6px 6px 0 var(--dark);
  width: 100%;
  margin: 0 0 2rem 0;
  background: var(--light);
  display: flex;
  flex-direction: column;
  border: 3px solid var(--dark);
  padding: 1.5rem;
  cursor: pointer;
  transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;
  -webkit-tap-highlight-color: transparent;
}

.neo-list-card:hover {
  transform: translateY(-4px);
  box-shadow: 6px 10px 0 var(--dark);
}

.neo-list-card.touch-active {
  transform: scale(0.97);
  box-shadow: 3px 3px 0 var(--dark);
  transition: transform 0.1s ease-out, box-shadow 0.1s ease-out;
}

.neo-list-header {
  font-weight: 900;
  font-size: 1.25rem;
  margin-bottom: 0.5rem;
  letter-spacing: 0.5px;
  color: var(--dark);
}

.neo-list-desc {
  font-size: 1rem;
  color: var(--dark);
  opacity: 0.7;
  margin-bottom: 1.2rem;
  font-weight: 500;
  line-height: 1.4;
}

.neo-item-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.neo-list-item {
  margin-bottom: 0.8rem;
  font-size: 1.05rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  position: relative;
}

.neo-list-item.is-updating .checkbox-text-span {
  opacity: 0.6;
}

.neo-checkbox-label {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 0.8em;
  cursor: pointer;
  position: relative;
  width: 100%;
  font-weight: 500;
  color: #414856;
  transition: color 0.3s ease;
}

.neo-checkbox-label input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  position: relative;
  height: 20px;
  width: 20px;
  outline: none;
  border: 2px solid #b8c1d1;
  margin: 0;
  cursor: pointer;
  background: transparent;
  border-radius: 6px;
  display: grid;
  align-items: center;
  justify-content: center;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.neo-checkbox-label input[type="checkbox"]:hover {
  border-color: var(--secondary);
  transform: scale(1.05);
}

.neo-checkbox-label input[type="checkbox"]::before,
.neo-checkbox-label input[type="checkbox"]::after {
  content: none;
}

.neo-checkbox-label input[type="checkbox"]::after {
  content: "";
  position: absolute;
  opacity: 0;
  left: 5px;
  top: 1px;
  width: 6px;
  height: 12px;
  border: solid var(--primary);
  border-width: 0 3px 3px 0;
  transform: rotate(45deg) scale(0);
  transition: all 0.2s cubic-bezier(0.18, 0.89, 0.32, 1.28);
  transition-property: transform, opacity;
}

.neo-checkbox-label input[type="checkbox"]:checked {
  border-color: var(--primary);
}

.neo-checkbox-label input[type="checkbox"]:checked::after {
  opacity: 1;
  transform: rotate(45deg) scale(1);
}

.checkbox-content {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
}

.checkbox-text-span {
  position: relative;
  transition: color 0.4s ease, opacity 0.4s ease;
  width: fit-content;
}

.checkbox-text-span::before {
  content: '';
  position: absolute;
  top: 50%;
  left: -0.1em;
  right: -0.1em;
  height: 2px;
  background: var(--dark);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.4s cubic-bezier(0.77, 0, .18, 1);
}

.checkbox-text-span::after {
  content: '';
  position: absolute;
  width: 6px;
  height: 6px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  pointer-events: none;
}

.neo-checkbox-label input[type="checkbox"]:checked~.checkbox-content .checkbox-text-span {
  color: var(--dark);
  opacity: 0.6;
}

.neo-checkbox-label input[type="checkbox"]:checked~.checkbox-content .checkbox-text-span::before {
  transform: scaleX(1);
  transform-origin: left;
  transition: transform 0.4s cubic-bezier(0.77, 0, .18, 1) 0.1s;
}

.neo-checkbox-label input[type="checkbox"]:checked~.checkbox-content .checkbox-text-span::after {
  animation: firework-refined 0.7s cubic-bezier(0.4, 0, 0.2, 1) forwards 0.2s;
}

.neo-completed-static {
  color: var(--dark);
  opacity: 0.6;
  position: relative;
}

.neo-completed-static::before {
  content: '';
  position: absolute;
  top: 50%;
  left: -0.1em;
  right: -0.1em;
  height: 2px;
  background: var(--dark);
  transform: scaleX(1);
  transform-origin: left;
}

.new-item-input-container .neo-checkbox-label {
  width: 100%;
}

.neo-new-item-input {
  all: unset;
  width: 100%;
  font-size: 1.05rem;
  font-weight: 500;
  color: #444;
  padding: 0.2rem 0;
  border-bottom: 1px dashed #ccc;
  transition: border-color 0.2s ease;
}

.neo-new-item-input:focus {
  border-bottom-color: var(--secondary);
}

.neo-new-item-input::placeholder {
  color: #999;
  font-weight: 400;
}

.neo-new-item-input:disabled {
  opacity: 0.7;
  cursor: not-allowed;
  background-color: transparent;
}

.neo-create-list-card {
  border: 3px dashed var(--dark);
  background: var(--light);
  padding: 2.5rem 0;
  text-align: center;
  font-weight: 900;
  font-size: 1.1rem;
  color: var(--dark);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  margin-bottom: 2.5rem;
  transition: all 0.15s ease-out;
}

.neo-create-list-card:hover {
  background: var(--light);
  transform: translateY(-3px) scale(1.01);
  box-shadow: 0px 6px 8px rgba(0, 0, 0, 0.05);
  color: var(--primary);
}

@media (max-width: 900px) {
  .neo-lists-grid {
    columns: 2 260px;
    column-gap: 1.2rem;
  }

  .neo-list-card,
  .neo-create-list-card {
    margin-bottom: 1.2rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }
}

@media (max-width: 600px) {
  .page-padding {
    padding: 0.5rem;
  }

  .neo-lists-grid {
    columns: 1 280px;
    column-gap: 1rem;
  }

  .neo-list-card {
    margin-bottom: 1rem;
    padding: 1rem;
    font-size: 1rem;
    min-height: 80px;
  }

  .neo-list-header {
    font-size: 1.1rem;
    margin-bottom: 0.3rem;
  }

  .neo-list-desc {
    font-size: 0.9rem;
    margin-bottom: 0.8rem;
  }

  .neo-checkbox-label input[type="checkbox"] {
    width: 1.4em;
    height: 1.4em;
  }

  .neo-list-item {
    margin-bottom: 0.7rem;
  }
}

@keyframes firework-refined {
  from {
    opacity: 1;
    transform: translate(-50%, -50%) scale(0.5);
    box-shadow: 0 0 0 0 var(--accent), 0 0 0 0 var(--accent), 0 0 0 0 var(--accent), 0 0 0 0 var(--accent), 0 0 0 0 var(--accent), 0 0 0 0 var(--accent), 0 0 0 0 var(--accent), 0 0 0 0 var(--accent);
  }

  to {
    opacity: 0;
    transform: translate(-50%, -50%) scale(2);
    box-shadow: 0 -20px 0 0 var(--accent), 20px 0px 0 0 var(--accent), 0 20px 0 0 var(--accent), -20px 0px 0 0 var(--accent), 14px -14px 0 0 var(--accent), 14px 14px 0 0 var(--accent), -14px 14px 0 0 var(--accent), -14px -14px 0 0 var(--accent);
  }
}

@keyframes error-flash {
  0% {
    background-color: var(--danger);
    opacity: 0.2;
  }

  100% {
    background-color: transparent;
    opacity: 0;
  }
}

@keyframes item-appear {
  0% {
    opacity: 0;
    transform: translateY(-15px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.error-flash {
  animation: error-flash 0.8s ease-out forwards;
}

.item-appear {
  animation: item-appear 0.35s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.archived {
  opacity: 0.6;
  background-color: #f0f0f0;
}

.actions {
  display: flex;
  gap: 0.5rem;
}
</style>
