<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { open as dialogOpen } from "@tauri-apps/plugin-dialog";

const screen = ref("login");
const serverUrl = ref("https://");
const username = ref("");
const password = ref("");
const loginError = ref("");
const loginLoading = ref(false);

const syncPaths = ref([]);
const syncLog = ref([]);
const syncing = ref(false);
const syncStatus = ref("Nicht verbunden");
const userInfo = ref(null);
const fileTree = ref([]);
const fileChanges = ref([]);
const autoSyncActive = ref(false);
const startMinimized = ref(false);

async function saveStartMinimized() {
  await invoke("set_start_minimized", { minimized: startMinimized.value });
}

// New sync path form
const showAddPath = ref(false);
const newPathLocal = ref("");
const newPathServerFolder = ref("");
const newPathServerId = ref(null);
const newPathMode = ref("virtual");
const serverFolders = ref([]);

// Local file browser
const localFiles = ref([]);
const localBreadcrumb = ref([]);
const contextMenu = ref({ show: false, x: 0, y: 0, file: null });

async function loadLocalFiles(subPath = null) {
  try {
    localFiles.value = await invoke("browse_sync_folder", { subPath });
    if (subPath) {
      // Build breadcrumb
      const sp = syncPaths.value[0];
      if (sp) {
        const rel = subPath.replace(sp.local_dir, "").replace(/^[/\\]/, "");
        const parts = rel.split(/[/\\]/).filter(Boolean);
        localBreadcrumb.value = [{ name: "Sync", path: sp.local_dir }];
        let current = sp.local_dir;
        for (const p of parts) {
          current += (current.endsWith("/") || current.endsWith("\\") ? "" : "/") + p;
          localBreadcrumb.value.push({ name: p, path: current });
        }
      }
    } else {
      localBreadcrumb.value = [];
    }
  } catch { localFiles.value = []; }
}

function openLocalFolder(file) {
  if (file.is_folder) loadLocalFiles(file.path);
}

function showContextMenu(e, file) {
  e.preventDefault();
  contextMenu.value = { show: true, x: e.clientX, y: e.clientY, file };
}

function hideContextMenu() {
  contextMenu.value = { show: false, x: 0, y: 0, file: null };
}

async function doMarkOffline(file) {
  hideContextMenu();
  try {
    const result = await invoke("mark_offline", { cloudPath: file.path });
    syncLog.value = [`[${ts()}] ${result}`, ...syncLog.value].slice(0, 200);
    await loadLocalFiles(null);
  } catch (err) {
    syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
  }
}

async function doUnlockFile(file) {
  hideContextMenu();
  const fileId = file.file_id ?? findFileInTree(fileTree.value, file.name)?.id;
  if (!fileId) {
    syncLog.value = [`[${ts()}] Fehler: Datei nicht auf Server gefunden`, ...syncLog.value];
    return;
  }
  try {
    await invoke("unlock_file_cmd", { fileId });
    syncLog.value = [`[${ts()}] Entsperrt: ${file.name}`, ...syncLog.value].slice(0, 200);
  } catch (err) {
    syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
  }
}

async function doLockOnly(file) {
  hideContextMenu();
  const fileId = file.file_id ?? findFileInTree(fileTree.value, file.name)?.id;
  if (!fileId) {
    syncLog.value = [`[${ts()}] Fehler: Datei nicht auf Server gefunden`, ...syncLog.value];
    return;
  }
  try {
    await invoke("lock_file_cmd", { fileId });
    syncLog.value = [`[${ts()}] Ausgecheckt: ${file.name}`, ...syncLog.value].slice(0, 200);
  } catch (err) {
    syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
  }
}

function findFileInTree(entries, name) {
  for (const e of entries) {
    if (e.name === name) return e;
    if (e.children) {
      const found = findFileInTree(e.children, name);
      if (found) return found;
    }
  }
  return null;
}

async function doUnmarkOffline(file) {
  hideContextMenu();
  try {
    const result = await invoke("unmark_offline", { cloudPath: file.path });
    syncLog.value = [`[${ts()}] ${result}`, ...syncLog.value].slice(0, 200);
    await loadLocalFiles(null);
  } catch (err) {
    syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
  }
}

async function doOpenCloudFile(file) {
  hideContextMenu();
  try {
    const realPath = await invoke("open_cloud_file", { cloudPath: file.path });
    syncLog.value = [`[${ts()}] Geoeffnet: ${realPath}`, ...syncLog.value].slice(0, 200);
  } catch (err) {
    syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
  }
}

async function doOpenOfflineFile(file) {
  hideContextMenu();
  try {
    await invoke("open_offline_file", { realPath: file.path });
    syncLog.value = [`[${ts()}] Ausgecheckt + geoeffnet: ${file.name}`, ...syncLog.value].slice(0, 200);
  } catch (err) {
    syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
  }
}

let unlistenStatus, unlistenLog, unlistenError, unlistenFileChange, unlistenTrigger, unlistenCloudOpen;

async function handleLogin() {
  loginError.value = "";
  loginLoading.value = true;
  try {
    const result = await invoke("login", {
      serverUrl: serverUrl.value,
      username: username.value,
      password: password.value,
    });
    userInfo.value = result;
    screen.value = "main";
    syncStatus.value = `Verbunden als ${result.username}`;
    startMinimized.value = await invoke("get_start_minimized");
    await loadFileTree();
    await loadSyncPaths();
  } catch (err) {
    loginError.value = String(err);
  } finally {
    loginLoading.value = false;
  }
}

async function loadFileTree() {
  try {
    fileTree.value = await invoke("get_file_tree");
    // Build flat folder list for sync path selection
    serverFolders.value = [{ id: null, name: "/ (Alle Dateien)", path: "/" }];
    flattenFolders(fileTree.value, "", serverFolders.value);
  } catch (err) { console.error(err); }
}

function flattenFolders(entries, prefix, list) {
  for (const e of entries) {
    if (e.is_folder) {
      const path = `${prefix}/${e.name}`;
      list.push({ id: e.id, name: path, path });
      if (e.children) flattenFolders(e.children, path, list);
    }
  }
}

async function loadSyncPaths() {
  try { syncPaths.value = await invoke("get_sync_paths"); }
  catch { syncPaths.value = []; }
}

async function browseFolder() {
  try {
    const selected = await dialogOpen({ directory: true, multiple: false, title: "Sync-Ordner waehlen" });
    if (selected) newPathLocal.value = selected;
  } catch { /* dialog cancelled */ }
}

async function addSyncPath() {
  if (!newPathLocal.value) return;
  try {
    await invoke("add_sync_path", {
      serverPath: newPathServerFolder.value || "/",
      serverFolderId: newPathServerId.value,
      localDir: newPathLocal.value,
      mode: newPathMode.value,
    });
    showAddPath.value = false;
    newPathLocal.value = "";
    newPathServerFolder.value = "";
    newPathServerId.value = null;
    newPathMode.value = "virtual";
    await loadSyncPaths();
    // Auto-start sync now that we have a path (if not already running)
    if (!autoSyncActive.value && syncPaths.value.length > 0) {
      await startSync();
    }
  } catch (err) { alert(err); }
}

async function removeSyncPath(id) {
  await invoke("remove_sync_path", { id });
  await loadSyncPaths();
  // If no paths remain, stop auto-sync
  if (syncPaths.value.length === 0) {
    autoSyncActive.value = false;
    syncStatus.value = "Keine Sync-Pfade konfiguriert";
  }
}

async function toggleMode(id) {
  await invoke("toggle_sync_mode", { id });
  await loadSyncPaths();
}

function selectServerFolder(folder) {
  newPathServerFolder.value = folder.path;
  newPathServerId.value = folder.id;
}

async function startSync() {
  syncing.value = true;
  syncStatus.value = "Erster Sync...";
  try {
    const log = await invoke("start_sync");
    syncLog.value = [...log.map(m => `[${ts()}] ${m}`), ...syncLog.value].slice(0, 200);
    syncStatus.value = "Synchronisiert";
    autoSyncActive.value = true;
    await loadFileTree();
    await loadLocalFiles(null);
  } catch (err) { syncStatus.value = `Fehler: ${err}`; }
  finally { syncing.value = false; }
}

async function syncNow() {
  syncing.value = true;
  try {
    const log = await invoke("run_sync_now");
    syncLog.value = [...log.map(m => `[${ts()}] ${m}`), ...syncLog.value].slice(0, 200);
    await loadFileTree();
  } catch (err) { syncStatus.value = `Fehler: ${err}`; }
  finally { syncing.value = false; }
}

function ts() {
  return new Date().toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit", second: "2-digit" });
}

function formatSize(b) {
  if (!b) return "";
  const u = ["B","KB","MB","GB"]; let i=0; let s=b;
  while (s>=1024 && i<u.length-1) { s/=1024; i++; }
  return `${s.toFixed(i>0?1:0)} ${u[i]}`;
}

onMounted(async () => {
  // Try auto-login with saved credentials
  try {
    const saved = await invoke("load_saved_config");
    if (saved.has_credentials) {
      loginLoading.value = true;
      serverUrl.value = saved.server_url;
      username.value = saved.username;
      try {
        const result = await invoke("auto_login");
        userInfo.value = result;
        screen.value = "main";
        syncStatus.value = `Verbunden als ${result.username}`;
        syncPaths.value = (await invoke("get_sync_paths"));
        startMinimized.value = await invoke("get_start_minimized");
        await loadFileTree();
        // Auto-start sync if paths configured
        if (syncPaths.value.length > 0) {
          await startSync();
        }
      } catch (err) {
        syncStatus.value = "Auto-Login fehlgeschlagen";
        // Show login screen with pre-filled fields
      }
      loginLoading.value = false;
    } else if (saved.has_config) {
      serverUrl.value = saved.server_url;
      username.value = saved.username;
    }
  } catch { /* no saved config */ }

  unlistenStatus = await listen("sync-status", e => {
    syncing.value = e.payload === "syncing";
    syncStatus.value = e.payload === "syncing" ? "Synchronisiere..." : "Synchronisiert";
    if (e.payload === "synced") { loadFileTree(); loadLocalFiles(null); }
  });
  unlistenLog = await listen("sync-log", e => {
    syncLog.value = [...e.payload.map(m => `[${ts()}] ${m}`), ...syncLog.value].slice(0, 200);
  });
  unlistenError = await listen("sync-error", e => {
    syncStatus.value = `Fehler: ${e.payload}`;
    syncing.value = false;
  });
  unlistenFileChange = await listen("file-change", e => {
    fileChanges.value = [`[${ts()}] ${e.payload}`, ...fileChanges.value].slice(0, 50);
  });
  unlistenTrigger = await listen("trigger-sync", () => syncNow());
  // Server-Push: bei jedem File-Event Server-Tree + Lokale Liste neu laden,
  // damit Lock-Status, neue/geloeschte Dateien sofort angezeigt werden.
  await listen("sse-event", () => {
    loadFileTree();
    loadLocalFiles(null);
  });
  unlistenCloudOpen = await listen("open-cloud-file", async (e) => {
    const cloudPath = e.payload;
    syncLog.value = [`[${ts()}] Oeffne: ${cloudPath}`, ...syncLog.value].slice(0, 200);
    try {
      const realPath = await invoke("open_cloud_file", { cloudPath });
      syncLog.value = [`[${ts()}] Geoeffnet: ${realPath}`, ...syncLog.value].slice(0, 200);
    } catch (err) {
      syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
    }
  });
});
onUnmounted(() => { unlistenStatus?.(); unlistenLog?.(); unlistenError?.(); unlistenFileChange?.(); unlistenTrigger?.(); unlistenCloudOpen?.(); });
</script>

<template>
  <!-- Login -->
  <div v-if="screen === 'login'" class="login-screen">
    <div class="login-card">
      <div class="login-header">
        <div class="logo-icon">☁</div>
        <h1>Mini-Cloud</h1>
        <p>Desktop Sync Client</p>
      </div>
      <form @submit.prevent="handleLogin">
        <div class="field"><label>Server-URL</label><input v-model="serverUrl" placeholder="https://cloud.example.com" /></div>
        <div class="field"><label>Benutzername</label><input v-model="username" autofocus /></div>
        <div class="field"><label>Passwort</label><input v-model="password" type="password" /></div>
        <div v-if="loginError" class="error">{{ loginError }}</div>
        <button type="submit" :disabled="loginLoading" class="btn-primary full">{{ loginLoading ? "Verbinde..." : "Anmelden" }}</button>
      </form>
    </div>
  </div>

  <!-- Main -->
  <div v-else class="main-screen">
    <div class="toolbar">
      <div class="toolbar-left">
        <span class="logo-small">☁</span><strong>Mini-Cloud Sync</strong>
        <span class="status-badge" :class="{ syncing, error: syncStatus.startsWith('Fehler') }">
          <span v-if="syncing" class="spin">⟳</span> {{ syncStatus }}
        </span>
      </div>
      <div class="toolbar-right"><span class="user-info">{{ userInfo?.username }}</span></div>
    </div>

    <div class="content">
      <!-- Sync Paths -->
      <div class="section">
        <div class="section-header">
          <h3>Sync-Pfade</h3>
          <div class="header-btns">
            <button v-if="syncPaths.length && !autoSyncActive" @click="startSync" :disabled="syncing" class="btn-primary">Sync starten</button>
            <button v-if="autoSyncActive" @click="syncNow" :disabled="syncing" class="btn-small">Jetzt synchronisieren</button>
            <button @click="showAddPath = !showAddPath" class="btn-small">+ Pfad hinzufuegen</button>
          </div>
        </div>

        <div v-if="autoSyncActive" class="auto-info">Auto-Sync alle 30s aktiv</div>

        <!-- Add new sync path -->
        <div v-if="showAddPath" class="add-path-form">
          <div class="field">
            <label>Server-Ordner</label>
            <select v-model="newPathServerId" @change="selectServerFolder(serverFolders.find(f => f.id === newPathServerId))">
              <option v-for="f in serverFolders" :key="f.id ?? 'root'" :value="f.id">{{ f.name }}</option>
            </select>
          </div>
          <div class="field">
            <label>Lokaler Ordner</label>
            <div class="browse-row">
              <input v-model="newPathLocal" placeholder="/home/user/MiniCloud" />
              <button @click="browseFolder" class="btn-small">Durchsuchen...</button>
            </div>
          </div>
          <div class="field">
            <label>Modus</label>
            <div class="mode-select">
              <label class="mode-option" :class="{ active: newPathMode === 'virtual' }">
                <input type="radio" v-model="newPathMode" value="virtual" /> ☁ Virtual Files
                <small>Platzhalter, Download bei Bedarf</small>
              </label>
              <label class="mode-option" :class="{ active: newPathMode === 'full' }">
                <input type="radio" v-model="newPathMode" value="full" /> 💾 Full Sync
                <small>Alle Dateien lokal spiegeln</small>
              </label>
            </div>
          </div>
          <div class="form-actions">
            <button @click="showAddPath = false" class="btn-small">Abbrechen</button>
            <button @click="addSyncPath" class="btn-primary" :disabled="!newPathLocal">Hinzufuegen</button>
          </div>
        </div>

        <!-- Existing sync paths -->
        <div v-for="sp in syncPaths" :key="sp.id" class="sync-path-card">
          <div class="sp-info">
            <div class="sp-server">☁ {{ sp.server_path }}</div>
            <div class="sp-arrow">→</div>
            <div class="sp-local">📁 {{ sp.local_dir }}</div>
          </div>
          <div class="sp-actions">
            <span class="sp-mode" :class="sp.mode" @click="toggleMode(sp.id)" :title="'Klicken zum Wechseln'">
              {{ sp.mode === 'Full' ? '💾 Full' : '☁ Virtual' }}
            </span>
            <button @click="removeSyncPath(sp.id)" class="btn-danger" title="Entfernen">✕</button>
          </div>
        </div>

        <div v-if="!syncPaths.length && !showAddPath" class="empty">
          Noch keine Sync-Pfade. Klicke "Pfad hinzufuegen" um loszulegen.
        </div>
      </div>

      <!-- Local File Browser -->
      <div v-if="autoSyncActive" class="section" @click="hideContextMenu">
        <div class="section-header">
          <h3>Lokale Dateien</h3>
          <button @click="loadLocalFiles(null)" class="btn-small">↻</button>
        </div>

        <div v-if="localBreadcrumb.length" class="local-breadcrumb">
          <span v-for="(b, i) in localBreadcrumb" :key="i">
            <a @click="loadLocalFiles(b.path)">{{ b.name }}</a>
            <span v-if="i < localBreadcrumb.length - 1"> / </span>
          </span>
        </div>

        <div class="local-file-list">
          <div v-for="f in localFiles" :key="f.path"
               class="local-file-item"
               @dblclick="f.is_folder ? openLocalFolder(f) : (f.is_cloud ? doOpenCloudFile(f) : doOpenOfflineFile(f))"
               @contextmenu="showContextMenu($event, f)">
            <span class="lf-icon">{{ f.is_folder ? '📁' : (f.is_cloud ? '☁' : '📄') }}</span>
            <span class="lf-name">{{ f.name }}</span>
            <span v-if="f.is_cloud" class="lf-badge cloud">Cloud</span>
            <span v-else-if="f.is_offline" class="lf-badge offline">Offline</span>
            <span v-if="f.locked" class="lf-badge locked" :title="'Ausgecheckt von ' + f.locked_by">🔒 {{ f.locked_by }}</span>
            <span class="lf-size">{{ formatSize(f.cloud_size || f.size) }}</span>
          </div>
          <div v-if="!localFiles.length" class="empty">Ordner ist leer</div>
        </div>
      </div>

      <!-- Context Menu -->
      <div v-if="contextMenu.show" class="context-menu"
           :style="{ left: contextMenu.x + 'px', top: contextMenu.y + 'px' }">
        <div v-if="contextMenu.file?.is_cloud" class="cm-item" @click="doOpenCloudFile(contextMenu.file)">
          📥 Oeffnen (herunterladen)
        </div>
        <div v-if="contextMenu.file?.is_cloud" class="cm-item" @click="doMarkOffline(contextMenu.file)">
          💾 Offline verfuegbar machen
        </div>
        <div v-if="contextMenu.file?.is_offline" class="cm-item" @click="doOpenOfflineFile(contextMenu.file)">
          📂 Oeffnen (auschecken)
        </div>
        <div v-if="contextMenu.file?.is_offline && !contextMenu.file?.locked" class="cm-item" @click="doLockOnly(contextMenu.file)">
          🔒 Auschecken (sperren)
        </div>
        <div v-if="contextMenu.file?.is_offline && contextMenu.file?.locked" class="cm-item" @click="doUnlockFile(contextMenu.file)">
          🔓 Entsperren (einchecken)
        </div>
        <div v-if="contextMenu.file?.is_offline" class="cm-item" @click="doUnmarkOffline(contextMenu.file)">
          ☁ Nicht mehr offline (Platzhalter)
        </div>
        <div class="cm-item" @click="hideContextMenu">Abbrechen</div>
      </div>

      <!-- File Tree -->
      <div class="section">
        <div class="section-header">
          <h3>Server-Dateien</h3>
          <button @click="loadFileTree" class="btn-small">↻</button>
        </div>
        <div class="file-tree">
          <template v-for="e in fileTree" :key="e.id">
            <div class="tree-item">
              <span class="tree-icon">{{ e.is_folder ? '📁' : '📄' }}</span>
              <span class="tree-name">{{ e.name }}</span>
              <span v-if="e.locked" class="tree-lock">🔒 {{ e.locked_by }}</span>
              <span v-if="!e.is_folder" class="tree-size">{{ formatSize(e.size) }}</span>
            </div>
            <div v-if="e.children" v-for="c in e.children" :key="c.id" class="tree-item indent">
              <span class="tree-icon">{{ c.is_folder ? '📁' : '📄' }}</span>
              <span class="tree-name">{{ c.name }}</span>
              <span v-if="c.locked" class="tree-lock">🔒 {{ c.locked_by }}</span>
              <span v-if="!c.is_folder" class="tree-size">{{ formatSize(c.size) }}</span>
            </div>
          </template>
          <div v-if="!fileTree.length" class="empty">Keine Dateien</div>
        </div>
      </div>

      <!-- File Changes -->
      <div v-if="fileChanges.length" class="section">
        <h3>Lokale Aenderungen</h3>
        <div class="log-list"><div v-for="(m,i) in fileChanges" :key="i" class="log-item change">{{ m }}</div></div>
      </div>

      <!-- Sync Log -->
      <div v-if="syncLog.length" class="section">
        <h3>Sync-Protokoll</h3>
        <div class="log-list"><div v-for="(m,i) in syncLog" :key="i" class="log-item">{{ m }}</div></div>
      </div>

      <!-- Settings -->
      <div class="section">
        <h3>Einstellungen</h3>
        <label class="checkbox-row">
          <input type="checkbox" v-model="startMinimized" @change="saveStartMinimized" />
          Minimiert starten (direkt im System-Tray)
        </label>
      </div>
    </div>
  </div>
</template>

<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;font-size:14px;color:#1a1a1a;background:#f0f2f5}
.login-screen{height:100vh;display:flex;align-items:center;justify-content:center}
.login-card{background:#fff;border-radius:12px;padding:2rem;width:360px;box-shadow:0 2px 12px rgba(0,0,0,.1)}
.login-header{text-align:center;margin-bottom:1.5rem}
.logo-icon{font-size:2.5rem}.login-header h1{font-size:1.3rem;margin:.5rem 0 .25rem}.login-header p{color:#666;font-size:.85rem}
.field{margin-bottom:.75rem}.field label{display:block;margin-bottom:.25rem;font-weight:500;font-size:.85rem}
.field input,.field select{width:100%;padding:.5rem;border:1px solid #ddd;border-radius:6px;font-size:.9rem;background:#fafafa}
.field input:focus,.field select:focus{border-color:#4a90d9;outline:none;background:#fff}
.error{color:#e53e3e;font-size:.85rem;margin-bottom:.75rem}
.btn-primary{padding:.5rem 1rem;background:#4a90d9;color:#fff;border:none;border-radius:6px;font-size:.85rem;cursor:pointer;font-weight:500;white-space:nowrap}
.btn-primary:hover{background:#3a7bc8}.btn-primary:disabled{opacity:.6;cursor:not-allowed}
.btn-primary.full{width:100%}
.btn-small{padding:.25rem .5rem;background:#e8e8e8;border:none;border-radius:4px;font-size:.8rem;cursor:pointer}
.btn-small:hover{background:#ddd}
.btn-danger{padding:.25rem .5rem;background:#fee;color:#c00;border:none;border-radius:4px;font-size:.8rem;cursor:pointer}
.btn-danger:hover{background:#fcc}
.main-screen{height:100vh;display:flex;flex-direction:column}
.toolbar{display:flex;align-items:center;justify-content:space-between;padding:.5rem 1rem;background:#fff;border-bottom:1px solid #e0e0e0}
.toolbar-left{display:flex;align-items:center;gap:.5rem}.logo-small{font-size:1.2rem}
.status-badge{font-size:.8rem;padding:.2rem .5rem;border-radius:4px;background:#e8f5e9;color:#2e7d32}
.status-badge.syncing{background:#fff3e0;color:#e65100}.status-badge.error{background:#ffebee;color:#c62828}
.spin{display:inline-block;animation:spin 1s linear infinite}@keyframes spin{from{transform:rotate(0)}to{transform:rotate(360deg)}}
.user-info{font-size:.85rem;color:#666}
.content{flex:1;overflow-y:auto;padding:1rem}
.section{background:#fff;border-radius:8px;padding:1rem;margin-bottom:.75rem}
.section h3{margin-bottom:.5rem;font-size:.95rem}
.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}
.section-header h3{margin:0}.header-btns{display:flex;gap:.5rem}
.auto-info{font-size:.8rem;color:#2e7d32;margin-bottom:.5rem}
.add-path-form{border:1px solid #e0e0e0;border-radius:8px;padding:1rem;margin-bottom:.75rem;background:#fafafa}
.browse-row{display:flex;gap:.5rem}
.browse-row input{flex:1}
.mode-select{display:flex;gap:.5rem}
.mode-option{flex:1;display:flex;flex-direction:column;padding:.5rem;border:2px solid #e0e0e0;border-radius:6px;cursor:pointer;font-size:.85rem}
.mode-option.active{border-color:#4a90d9;background:#f0f7ff}
.mode-option input{margin-right:.25rem}
.mode-option small{color:#888;font-size:.75rem;margin-top:.25rem}
.form-actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem}
.sync-path-card{display:flex;align-items:center;justify-content:space-between;padding:.5rem .75rem;border:1px solid #e8e8e8;border-radius:6px;margin-bottom:.375rem;font-size:.85rem}
.sp-info{display:flex;align-items:center;gap:.375rem;flex:1;min-width:0}
.sp-server,.sp-local{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sp-server{color:#4a90d9}.sp-arrow{color:#999;flex-shrink:0}.sp-local{color:#555}
.sp-actions{display:flex;align-items:center;gap:.375rem;flex-shrink:0}
.sp-mode{font-size:.75rem;padding:.2rem .4rem;border-radius:4px;cursor:pointer;background:#f0f0f0}
.sp-mode.Full{background:#e3f2fd;color:#1565c0}.sp-mode.Virtual{background:#f3e5f5;color:#7b1fa2}
.file-tree{max-height:250px;overflow-y:auto}
.tree-item{display:flex;align-items:center;gap:.5rem;padding:.3rem 0;border-bottom:1px solid #f5f5f5;font-size:.85rem}
.tree-item.indent{padding-left:1.5rem}.tree-icon{flex-shrink:0}.tree-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tree-lock{font-size:.75rem;color:#e67e22;flex-shrink:0}.tree-size{font-size:.75rem;color:#999;flex-shrink:0}
.empty{text-align:center;color:#999;padding:1rem;font-size:.85rem}
.log-list{max-height:150px;overflow-y:auto;font-family:monospace;font-size:.78rem}
.log-item{padding:.2rem 0;border-bottom:1px solid #f8f8f8;color:#555}.log-item.change{color:#1565c0}
.local-breadcrumb{font-size:.85rem;margin-bottom:.5rem;color:#666}
.local-breadcrumb a{color:#4a90d9;cursor:pointer;text-decoration:none}
.local-breadcrumb a:hover{text-decoration:underline}
.local-file-list{max-height:300px;overflow-y:auto}
.local-file-item{display:flex;align-items:center;gap:.5rem;padding:.35rem .25rem;border-bottom:1px solid #f5f5f5;font-size:.85rem;cursor:default;user-select:none}
.local-file-item:hover{background:#f8f8f8}
.lf-icon{flex-shrink:0;font-size:1rem}
.lf-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lf-badge{font-size:.65rem;padding:.1rem .3rem;border-radius:3px;flex-shrink:0}
.lf-badge.cloud{background:#e3f2fd;color:#1565c0}
.lf-badge.offline{background:#e8f5e9;color:#2e7d32}
.lf-badge.locked{background:#fff3e0;color:#e65100}
.lf-size{font-size:.75rem;color:#999;flex-shrink:0}
.checkbox-row{display:flex;align-items:center;gap:.5rem;font-size:.85rem;cursor:pointer}
.context-menu{position:fixed;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);z-index:9999;min-width:200px;padding:.25rem 0}
.cm-item{padding:.5rem .75rem;cursor:pointer;font-size:.85rem}
.cm-item:hover{background:#f0f0f0}
@media(prefers-color-scheme:dark){body{color:#e0e0e0;background:#1a1a1a}.login-card,.section{background:#2a2a2a}.toolbar{background:#2a2a2a;border-color:#3a3a3a}.field input,.field select{background:#333;border-color:#444;color:#e0e0e0}.status-badge{background:#1b5e20;color:#a5d6a7}.status-badge.syncing{background:#e65100;color:#ffcc80}.add-path-form{background:#333;border-color:#444}.mode-option{border-color:#444}.mode-option.active{border-color:#4a90d9;background:#1a3a5c}.sync-path-card{border-color:#3a3a3a}.tree-item{border-color:#333}.log-item{border-color:#333;color:#aaa}.log-item.change{color:#64b5f6}.local-file-item{border-color:#333}.local-file-item:hover{background:#333}.context-menu{background:#2a2a2a;border-color:#444}.cm-item:hover{background:#3a3a3a}}
</style>
