⬅ חזרה לתיקייה · הורד קובץ · ערוך

📄 index_before_budget_20260715_171305.html

C:\TripServer\backups\Moneyapp\index_before_budget_20260715_171305.html

<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ניהול תקציב חופשה</title>

<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.2/firebase-app.js";
import { getAuth, onAuthStateChanged, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut } from "https://www.gstatic.com/firebasejs/10.12.2/firebase-auth.js";
import { initializeFirestore, persistentLocalCache, persistentMultipleTabManager, collection, addDoc, setDoc, doc, getDocs, getDocFromServer, getDocsFromServer, deleteDoc, onSnapshot } from "https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore.js";

const firebaseConfig = {
  apiKey: "AIzaSyDJVmdnQw6ZV3sFOc04EMkYob735XATKBM",
  authDomain: "vaction-budget.firebaseapp.com",
  projectId: "vaction-budget",
  storageBucket: "vaction-budget.firebasestorage.app",
  messagingSenderId: "1039853800467",
  appId: "1:1039853800467:web:6ab326be5e04fe8bbc43e6",
  measurementId: "G-35QMXX5D01"
};

const app = initializeApp(firebaseConfig);
const db = initializeFirestore(app, {
  localCache: persistentLocalCache({
    tabManager: persistentMultipleTabManager()
  })
});
const auth = getAuth(app);

const budgetILS = 93063;
const clothingBudgetILS = 20000;
const foodDailyBudgetILS = 750;

const allowedEmails = [
  "eitan.fridman@gmail.com",
  "eitan.friedman@gmail.com",
  "karin.enoshi@gmail.com"
].map(e => e.toLowerCase());

let pendingOfflineWrites = Number(localStorage.getItem("pendingOfflineWrites") || "0");
let appDataStarted = false;
const BUDGET_APP_VERSION = "2026.07.15-FX-KIDS-v4";

function authMsg(text){
  const el = document.getElementById("authMessage");
  if(el) el.innerText = text || "";
}

function isAllowedUser(user){
  return !!(user && user.email && allowedEmails.includes(user.email.toLowerCase()));
}

window.loginBudgetApp = async function(){
  const email = document.getElementById("authEmail")?.value.trim();
  const password = document.getElementById("authPassword")?.value;
  if(!email || !password){ authMsg("יש להזין אימייל וסיסמה."); return; }
  try{
    authMsg("מתחבר...");
    await signInWithEmailAndPassword(auth, email, password);
  }catch(err){
    authMsg("כניסה נכשלה. בדוק אימייל/סיסמה.");
  }
};

window.createBudgetUser = async function(){
  const email = document.getElementById("authEmail")?.value.trim();
  const password = document.getElementById("authPassword")?.value;
  if(!email || !password){ authMsg("יש להזין אימייל וסיסמה ליצירת משתמש."); return; }
  if(!allowedEmails.includes(email.toLowerCase())){
    authMsg("המייל הזה לא נמצא ברשימת המורשים בקובץ.");
    return;
  }
  try{
    authMsg("יוצר משתמש...");
    await createUserWithEmailAndPassword(auth, email, password);
  }catch(err){
    if(String(err.code || "").includes("email-already-in-use")) authMsg("המשתמש כבר קיים. אפשר ללחוץ כניסה.");
    else if(String(err.code || "").includes("weak-password")) authMsg("הסיסמה חלשה מדי. צריך לפחות 6 תווים.");
    else authMsg("יצירת המשתמש נכשלה.");
  }
};

window.logoutBudgetApp = async function(){
  await signOut(auth);
};

function showAppForUser(user){
  document.body.classList.remove("authLocked");
  const overlay = document.getElementById("authOverlay");
  if(overlay) overlay.style.display = "none";
  const topBar = document.getElementById("authTopBar");
  if(topBar) topBar.style.display = "flex";
  const label = document.getElementById("authUserLabel");
  if(label) label.innerText = "מחובר: " + (user.email || "");
  updateConnectionStatus();
  if(typeof initAppTabs === 'function') setTimeout(initAppTabs, 80);
}

function showAuthScreen(message){
  document.body.classList.add("authLocked");
  const overlay = document.getElementById("authOverlay");
  if(overlay) overlay.style.display = "flex";
  const topBar = document.getElementById("authTopBar");
  if(topBar) topBar.style.display = "none";
  authMsg(message || "");
}

function setSyncStatus(mode, text, sub){
  const bar = document.getElementById("syncStatusBar");
  const txt = document.getElementById("syncStatusText");
  const subEl = document.getElementById("syncStatusSub");
  if(!bar || !txt || !subEl) return;
  bar.classList.remove("online","offline","pending");
  bar.classList.add(mode);
  txt.innerText = text;
  subEl.innerText = sub || "";
}

function updateConnectionStatus(){
  if(!navigator.onLine){
    setSyncStatus("offline", "מצב אופליין", "אפשר להזין הוצאות. הן יישמרו במכשיר ויסונכרנו כשיחזור אינטרנט.");
    return;
  }
  if(pendingOfflineWrites > 0){
    setSyncStatus("pending", "חזרת לרשת — מסנכרן נתונים...", "יש פעולות שהוזנו אופליין וממתינות לאישור Firebase.");
    return;
  }
  setSyncStatus("online", "מחובר ומסונכרן", "כל שינוי נשמר מול Firebase ומסתנכרן עם המכשיר השני.");
}

window.addEventListener("online", () => {
  updateConnectionStatus();
  setTimeout(() => {
    pendingOfflineWrites = 0;
    localStorage.setItem("pendingOfflineWrites", "0");
    updateConnectionStatus();
    if(typeof renderAll === "function") renderAll();
  }, 2500);
});

window.addEventListener("offline", updateConnectionStatus);

let lastCloudRefreshAt = 0;
document.addEventListener("visibilitychange", () => {
  if(!document.hidden && auth.currentUser && isAllowedUser(auth.currentUser)){
    const now = Date.now();
    if(now - lastCloudRefreshAt > 10000){
      lastCloudRefreshAt = now;
      forceFirebaseServerRefresh("חזרה לאפליקציה");
    }
  }
});
window.addEventListener("focus", () => {
  if(auth.currentUser && isAllowedUser(auth.currentUser)){
    const now = Date.now();
    if(now - lastCloudRefreshAt > 10000){
      lastCloudRefreshAt = now;
      forceFirebaseServerRefresh("חזרה לחלון");
    }
  }
});


function markLocalWriteAttempt(){
  if(!navigator.onLine){
    pendingOfflineWrites += 1;
    localStorage.setItem("pendingOfflineWrites", String(pendingOfflineWrites));
  }
  updateConnectionStatus();
}

function markWriteConfirmed(){
  if(navigator.onLine && pendingOfflineWrites > 0){
    pendingOfflineWrites = Math.max(0, pendingOfflineWrites - 1);
    localStorage.setItem("pendingOfflineWrites", String(pendingOfflineWrites));
  }
  updateConnectionStatus();
}

async function trackedWrite(operation){
  markLocalWriteAttempt();
  try{
    const result = await operation();
    markWriteConfirmed();
    return result;
  }catch(err){
    updateConnectionStatus();
    throw err;
  }
}

function trackedSetDoc(ref, data, options){
  return trackedWrite(() => setDoc(ref, data, options));
}

function trackedAddDoc(ref, data){
  return trackedWrite(() => addDoc(ref, data));
}

function trackedDeleteDoc(ref){
  return trackedWrite(() => deleteDoc(ref));
}

onAuthStateChanged(auth, async (user) => {
  if(!user){
    showAuthScreen("");
    return;
  }
  if(!isAllowedUser(user)){
    await signOut(auth);
    showAuthScreen("המשתמש הזה לא מורשה להיכנס לאפליקציה.");
    return;
  }
  showAppForUser(user);
  if(!appDataStarted){
    appDataStarted = true;
    startBudgetAppData();
  }
});


const tripBudgetDefaults = {
  japan_2026: {
    aliases: ["japan_2026", "יפן 2026", "Japan 2026"],
    dailyFoodBudget: 750,
    totalFoodBudget: 0,
    shoppingBudget: 20000,
    totalBudget: 93063
  },
  usa_2027: {
    aliases: [
      "usa_2027",
      "ארה״ב 2027",
      "ארהב 2027",
      "ארצות הברית 2027",
      "טיול ארה״ב 2027",
      "טיול ארהב 2027",
      "USA 2027",
      "US 2027",
      "United States 2027"
    ],
    dailyFoodBudget: 900,
    totalFoodBudget: 27000,
    shoppingBudget: 30000,
    totalBudget: 246000
  },
  custom: {
    aliases: [],
    dailyFoodBudget: foodDailyBudgetILS,
    totalFoodBudget: 0,
    shoppingBudget: clothingBudgetILS,
    totalBudget: budgetILS
  }
};

function normalizeTripText(v){
  return String(v || "")
    .trim()
    .replace(/"/g, "״")
    .replace(/\s+/g, " ")
    .toLowerCase();
}

function getTripDefaultBudgetProfile(trip = {}){
  const rawKeys = [trip.id, trip.name, trip.tripName, activeTripId].filter(Boolean);
  const keysToCheck = rawKeys.map(normalizeTripText);
  const joined = keysToCheck.join(" ");

  if(joined.includes("usa") || joined.includes("us 2027") || joined.includes("ארהב") || joined.includes("ארה״ב") || joined.includes("ארצות הברית")){
    return tripBudgetDefaults.usa_2027;
  }

  if(joined.includes("japan") || joined.includes("יפן")){
    return tripBudgetDefaults.japan_2026;
  }

  for(const key of Object.keys(tripBudgetDefaults)){
    const cfg = tripBudgetDefaults[key];
    const aliases = [key, ...(cfg.aliases || [])].map(normalizeTripText);
    if(keysToCheck.some(k => aliases.includes(k))){
      return cfg;
    }
  }

  return tripBudgetDefaults.custom;
}

function cleanBudgetNumber(value, fallback = 0){
  const n = Number(value);
  return Number.isFinite(n) && n >= 0 ? n : Number(fallback || 0);
}

function normalizeBudgetSources(trip = getActiveTrip()){
  const defaults = getTripDefaultBudgetProfile(trip);
  const raw = Array.isArray(trip.budgetSources) ? trip.budgetSources : [];
  const sources = raw
    .map((src, index) => ({
      id: String(src?.id || `source_${index}`),
      amount: cleanBudgetNumber(src?.amount, 0),
      currency: ["ILS","USD","JPY","EUR","GBP","CAD"].includes(src?.currency) ? src.currency : "ILS"
    }))
    .filter(src => src.amount > 0);

  if(!sources.length){
    sources.push({id:"legacy_ils", amount:cleanBudgetNumber(trip.budgetILS, defaults.totalBudget), currency:"ILS"});
  }
  return sources;
}

function getTripBudgetSourcesILS(trip = getActiveTrip()){
  return normalizeBudgetSources(trip).reduce((sum, src) => sum + convertToILS(src.amount, src.currency, rates), 0);
}

function getTripBudgetConfig(trip = getActiveTrip()){
  const defaults = getTripDefaultBudgetProfile(trip);
  return {
    totalBudget: getTripBudgetSourcesILS(trip),
    budgetSources: normalizeBudgetSources(trip),
    idoPrivateBudget: cleanBudgetNumber(trip.idoPrivateBudgetILS, 0),
    michaelPrivateBudget: cleanBudgetNumber(trip.michaelPrivateBudgetILS, 0),
    shoppingBudget: cleanBudgetNumber(trip.clothingBudgetILS, defaults.shoppingBudget),
    dailyFoodBudget: cleanBudgetNumber(trip.foodDailyBudgetILS, defaults.dailyFoodBudget),
    totalFoodBudget: cleanBudgetNumber(trip.totalFoodBudgetILS, defaults.totalFoodBudget || 0)
  };
}

function budgetOwnerKey(e){
  return ["home","ido","michael"].includes(e?.budgetOwner) ? e.budgetOwner : "home";
}

function budgetOwnerLabel(owner){
  return owner === "ido" ? "תקציב עידו פרטי" : owner === "michael" ? "תקציב מיכאל פרטי" : "תקציב הבית";
}

function getOwnerExpenses(owner, tripId = activeTripId){
  return getTripExpenses(tripId).filter(e => budgetOwnerKey(e) === owner);
}

function getOwnerSpentILS(owner, tripId = activeTripId){
  return getOwnerExpenses(owner, tripId).reduce((sum,e) => sum + expenseILS(e), 0);
}

function getOwnerBudgetILS(owner, trip = getActiveTrip()){
  const cfg = getTripBudgetConfig(trip);
  if(owner === "ido") return cfg.idoPrivateBudget;
  if(owner === "michael") return cfg.michaelPrivateBudget;
  return cfg.totalBudget;
}

function getCurrentTripBudgetConfig(){
  return getTripBudgetConfig(getActiveTrip());
}

function getTripExpenses(tripId){
  return expenses.filter(e => (e.tripId || defaultTrip.id) === tripId);
}

function getTripTotalILS(tripId){
  return getTripExpenses(tripId).reduce((s,e)=>s + expenseILS(e), 0);
}

function getTripShoppingILS(tripId){
  return getTripExpenses(tripId)
    .filter(e => budgetOwnerKey(e) === "home")
    .filter(e => {
      const cat = (e.category || "").trim();
      return cat.includes("קניות") || cat.includes("ביגוד");
    })
    .reduce((s,e)=>s + expenseILS(e), 0);
}


window.showAppTab = function(tabId, shouldScroll = true){
  const map = {
    tabMain: "tab-main",
    tabSummary: "tab-summary",
    tabCharts: "tab-charts",
    tabCompare: "tab-compare",
    tabSettings: "tab-settings"
  };
  const scrollMap = {
    tabMain: "tabMain",
    tabSummary: "summaryAnchor",
    tabCharts: "chartsInfoAnchor",
    tabCompare: "compareAnchor",
    tabSettings: "settingsExportAnchor"
  };
  const cls = map[tabId] || "tab-main";

  document.body.classList.remove("tab-main","tab-summary","tab-charts","tab-compare","tab-settings");
  document.body.classList.add(cls);

  document.querySelectorAll(".tabPanel").forEach(p => p.classList.remove("active"));
  const panel = document.getElementById(tabId);
  if(panel) panel.classList.add("active");

  document.querySelectorAll(".appTabs button").forEach(b => b.classList.remove("active"));
  const btn = document.querySelector(`[data-tab-btn="${tabId}"]`);
  if(btn) btn.classList.add("active");

  localStorage.setItem("activeBudgetTab", tabId);

  if(typeof renderExpenses === "function") setTimeout(renderExpenses, 60);
  if(tabId === "tabCharts" && typeof renderDashboard === "function") setTimeout(renderDashboard, 120);
  if(typeof applyMobileTableLabels === "function") setTimeout(applyMobileTableLabels, 90);

  if(shouldScroll){
    const target = document.getElementById(scrollMap[tabId] || tabId) || panel;
    if(target){
      setTimeout(() => {
        try{
          target.scrollIntoView({behavior:"smooth", block:"start"});
        }catch(err){
          target.scrollIntoView(true);
        }
      }, 60);
    }
  }
};

function initAppTabs(){
  const saved = localStorage.getItem("activeBudgetTab") || "tabMain";
  showAppTab(saved, false);
}

const defaultRates = {
  USD: 2.9090,
  JPY: 0.018511,
  EUR: 3.4225,
  GBP: 3.9572,
  CAD: 2.1282,
  source: "בנק ישראל",
  updatedAtText: "11/05/2026",
  note: "USD 2.9090, JPY 0.018511, EUR 3.4225, GBP 3.9572, CAD 2.1282"
};

let rates = {...defaultRates};
let expenses = [];
let tripName = "";
let legacyFreezeRunning = false;

const FOREIGN_CREDIT_FEE_RATE = 0.01;

function paymentMethodLabel(method){
  return method === "credit" ? "אשראי" : "מזומן";
}

function isForeignCreditExpense(currency, paymentMethod){
  return currency !== "ILS" && paymentMethod === "credit";
}

function baseExpenseILSValue(e){
  if(typeof e.baseIlsAtEntry === "number") return e.baseIlsAtEntry;
  if(typeof e.ilsAtEntry === "number" && typeof e.foreignCreditFeeILS === "number") return Math.max(0, e.ilsAtEntry - e.foreignCreditFeeILS);
  return convertToILS(e.amount, e.currency, rates);
}

function foreignCreditFeeILSValue(e){
  if(typeof e.foreignCreditFeeILS === "number") return e.foreignCreditFeeILS;
  return 0;
}

function formatExpenseTotalCell(e){
  const total = expenseILS(e);
  const fee = foreignCreditFeeILSValue(e);
  const base = baseExpenseILSValue(e);
  if(fee > 0){
    return `<b>${fmtILS(total)}</b><br><span class="expenseSubLine">בסיס: ${fmtILS(base)}<br>עמלת אשראי מט״ח 1%: ${fmtILS(fee)}</span>`;
  }
  return `<b>${fmtILS(total)}</b>`;
}

function renderExpenseFeePreview(){
  const box = document.getElementById("fxFeePreview");
  if(!box) return;
  const amount = Number(document.getElementById("amount")?.value || 0);
  const currency = document.getElementById("currency")?.value || "ILS";
  const paymentMethod = document.getElementById("paymentMethod")?.value || "credit";

  if(!amount || amount <= 0){
    box.innerHTML = "הזן סכום כדי לראות את חישוב השקלים והאם יש עמלת אשראי מט״ח.";
    box.classList.remove("feeActive");
    return;
  }

  const rateSnapshot = {
    USD: Number(rates.USD),
    JPY: Number(rates.JPY),
    EUR: Number(rates.EUR),
    GBP: Number(rates.GBP),
    CAD: Number(rates.CAD)
  };
  const baseILS = convertToILS(amount, currency, rateSnapshot);
  const feeILS = isForeignCreditExpense(currency, paymentMethod) ? baseILS * FOREIGN_CREDIT_FEE_RATE : 0;
  const totalILS = baseILS + feeILS;

  if(currency === "ILS"){
    box.innerHTML = `<b>עסקה בשקלים:</b> ${fmtILS(totalILS)}. אין עמלת מט״ח.`;
    box.classList.remove("feeActive");
    return;
  }

  if(paymentMethod !== "credit"){
    box.innerHTML = `<b>מזומן במטבע זר:</b> ${fmtILS(baseILS)} לפי שער פעיל. אין עמלת אשראי מט״ח.`;
    box.classList.remove("feeActive");
    return;
  }

  box.innerHTML = `<b>אשראי במטבע זר:</b><br>סכום מקורי בשקלים: ${fmtILS(baseILS)}<br>עמלת אשראי מט״ח 1%: ${fmtILS(feeILS)}<br><b>סה״כ שיירשם בתקציב: ${fmtILS(totalILS)}</b>`;
  box.classList.add("feeActive");
}

const fixedCategories = [
  "כרטיסי סים",
  "אוכל",
  "קניות עידו",
  "קניות מיכאל",
  "ביגוד והנעלה",
  "תחבורה ציבורית",
  "אטרקציות",
  "תשלומים במזומן",
  "מלונות",
  "ביטוח נסיעות",
  "טיסות",
  "השכרת רכב",
  "דלק",
  "טיפים",
  "כביסות",
  "קרוז",
  "שונות"
];

let currentFilterType = "category";
let currentCategoryFilter = "ALL";
let currentDateFilter = "ALL";
let summaryCurrencyCode = "ILS";
let currentCompareMetric = "TOTAL";
let currentCompareDate = "ALL";

let trips = [];
let activeTripId = localStorage.getItem("activeTripId") || "japan_2026";
const defaultTrip = {
  id: "japan_2026",
  name: "יפן 2026",
  budgetILS: 93063,
  clothingBudgetILS: 20000,
  foodDailyBudgetILS: 750,
  budgetSources: [{id:"legacy_ils", amount:93063, currency:"ILS"}],
  idoPrivateBudgetILS: 0,
  michaelPrivateBudgetILS: 0,
  created: 0
};


function safeTripId(name){
  const base = String(name || "trip").trim()
    .replace(/[\s]+/g, "_")
    .replace(/[^֐-׿a-zA-Z0-9_\-]/g, "")
    .slice(0, 40);
  return (base || "trip") + "_" + Date.now();
}

function getActiveTrip(){
  return trips.find(t => t.id === activeTripId) || defaultTrip;
}

function getActiveBudgetILS(){
  return Number(getCurrentTripBudgetConfig().totalBudget || 0);
}

function getActiveClothingBudgetILS(){
  return Number(getCurrentTripBudgetConfig().shoppingBudget || 0);
}

function getActiveFoodDailyBudgetILS(){
  return Number(getCurrentTripBudgetConfig().dailyFoodBudget || 0);
}

function allExpenses(){
  return expenses;
}

function activeExpenses(){
  return expenses.filter(e => (e.tripId || "japan_2026") === activeTripId);
}

function visibleExpenses(){
  let list = activeExpenses();

  if(currentFilterType === "category" && currentCategoryFilter !== "ALL"){
    list = list.filter(e => e.category === currentCategoryFilter);
  }

  if(currentFilterType === "date" && currentDateFilter !== "ALL"){
    list = list.filter(e => e.date === currentDateFilter);
  }

  return list;
}

function activeFilterDescription(){
  if(currentFilterType === "category" && currentCategoryFilter !== "ALL"){
    return "קטגוריה: " + currentCategoryFilter;
  }
  if(currentFilterType === "date" && currentDateFilter !== "ALL"){
    return "תאריך: " + currentDateFilter;
  }
  return "כל ההוצאות בטיול הפעיל";
}

function fmtILS(n){ return "₪" + Number(n || 0).toLocaleString("he-IL", {minimumFractionDigits:2, maximumFractionDigits:2}); }
function fmtUSD(n){ return "$" + Number(n || 0).toLocaleString("en-US", {minimumFractionDigits:2, maximumFractionDigits:2}); }
function fmtJPY(n){ return "¥" + Number(n || 0).toLocaleString("ja-JP", {maximumFractionDigits:0}); }

function fmtCurrencyByCode(n, code){
  n = Number(n || 0);
  if(code === "ILS") return fmtILS(n);
  if(code === "USD") return "$" + n.toLocaleString("en-US", {minimumFractionDigits:2, maximumFractionDigits:2});
  if(code === "JPY") return "¥" + n.toLocaleString("ja-JP", {maximumFractionDigits:0});
  if(code === "EUR") return "€" + n.toLocaleString("de-DE", {minimumFractionDigits:2, maximumFractionDigits:2});
  if(code === "GBP") return "£" + n.toLocaleString("en-GB", {minimumFractionDigits:2, maximumFractionDigits:2});
  if(code === "CAD") return "C$" + n.toLocaleString("en-CA", {minimumFractionDigits:2, maximumFractionDigits:2});
  return fmtILS(n);
}

function convertFromILS(amountILS, code){
  amountILS = Number(amountILS || 0);
  if(code === "ILS") return amountILS;
  return amountILS / Number(rates[code] || 1);
}

function currencyLabel(code){
  const labels = {
    ILS: "שקל ישראלי",
    USD: "דולר אמריקאי",
    JPY: "ין יפני",
    EUR: "יורו",
    GBP: "לירה סטרלינג",
    CAD: "דולר קנדי"
  };
  return labels[code] || "שקל ישראלי";
}

function todayText(){ return new Date().toLocaleDateString("he-IL"); }

function isoToday(){
  const d = new Date();
  const offset = d.getTimezoneOffset();
  const local = new Date(d.getTime() - offset * 60000);
  return local.toISOString().slice(0,10);
}

function heDateToISO(dateText){
  const s = String(dateText || "").trim();
  const m = s.match(/^(\d{1,2})[./-](\d{1,2})[./-](\d{2,4})$/);
  if(!m) return "";
  const day = m[1].padStart(2,"0");
  const month = m[2].padStart(2,"0");
  const year = m[3].length === 2 ? "20" + m[3] : m[3];
  return `${year}-${month}-${day}`;
}

function isoToHeDate(iso){
  const s = String(iso || "").trim();
  const m = s.match(/^(\d{4})-(\d{2})-(\d{2})$/);
  if(!m) return todayText();
  return `${Number(m[3])}.${Number(m[2])}.${m[1]}`;
}

function dateSortKey(dateText){
  return heDateToISO(dateText) || String(dateText || "");
}

function expenseDateTextFromInput(){
  const input = document.getElementById("expenseDate");
  return input?.value ? isoToHeDate(input.value) : todayText();
}

function ensureExpenseDateDefault(){
  const input = document.getElementById("expenseDate");
  if(input && !input.value) input.value = isoToday();
}

function setExpenseDateInput(dateText){
  const input = document.getElementById("expenseDate");
  if(input) input.value = heDateToISO(dateText) || isoToday();
}

function escapeHtml(text){
  return String(text || "")
    .replaceAll("&","&amp;")
    .replaceAll("<","&lt;")
    .replaceAll(">","&gt;")
    .replaceAll('"',"&quot;")
    .replaceAll("'","&#039;");
}

function convertToILS(amount, currency, rateSnapshot = rates){
  amount = Number(amount || 0);
  if(currency === "ILS") return amount;
  if(currency === "USD") return amount * Number(rateSnapshot.USD);
  if(currency === "JPY") return amount * Number(rateSnapshot.JPY);
  if(currency === "EUR") return amount * Number(rateSnapshot.EUR);
  if(currency === "GBP") return amount * Number(rateSnapshot.GBP);
  if(currency === "CAD") return amount * Number(rateSnapshot.CAD);
  return amount;
}

function expenseILS(e){
  if(typeof e.ilsAtEntry === "number") return e.ilsAtEntry;
  return convertToILS(e.amount, e.currency, rates);
}

async function ensureDefaultSettings(){
  const ratesRef = doc(db, "settings", "rates");
  const defaultTripRef = doc(db, "trips", "japan_2026");
  try{
    const [ratesSnap, tripSnap] = await Promise.all([
      getDocFromServer(ratesRef),
      getDocFromServer(defaultTripRef)
    ]);

    if(!ratesSnap.exists()){
      await trackedSetDoc(ratesRef, defaultRates, {merge:true});
    }

    if(!tripSnap.exists()){
      await trackedSetDoc(defaultTripRef, {...defaultTrip, id:"japan_2026", name:"יפן 2026"}, {merge:true});
    }
  }catch(err){
    console.warn("Default settings check skipped", err);
  }
}

window.saveTripName = async function(){
  const name = document.getElementById("tripName").value.trim();
  tripName = name;
  const trip = getActiveTrip();
  const updatedTrip = {
    ...trip,
    id: activeTripId,
    name: name || trip.name || "טיול ללא שם"
  };
  await trackedSetDoc(doc(db, "trips", activeTripId), updatedTrip, {merge:true});
  trips = trips.some(t => t.id === activeTripId)
    ? trips.map(t => t.id === activeTripId ? {...t, ...updatedTrip} : t)
    : [...trips, updatedTrip];
  renderTripSelector();
  renderHomeTripSelector();
  renderHomeSummary();
};

window.saveManualRates = async function(){
  const usd = Number(document.getElementById("usdRateInput").value);
  const jpy = Number(document.getElementById("jpyRateInput").value);
  const eur = Number(document.getElementById("eurRateInput").value);
  const gbp = Number(document.getElementById("gbpRateInput").value);
  const cad = Number(document.getElementById("cadRateInput").value);
  if(!usd || !jpy || !eur || !gbp || !cad || usd <= 0 || jpy <= 0 || eur <= 0 || gbp <= 0 || cad <= 0){
    alert("הכנס שערים תקינים לכל המטבעות");
    return;
  }

  const manualRates = {
    USD: usd,
    JPY: jpy,
    EUR: eur,
    GBP: gbp,
    CAD: cad,
    source: "עדכון ידני",
    updatedAtText: new Date().toLocaleString("he-IL"),
    note: "שערים ידניים"
  };

  await trackedSetDoc(doc(db, "settings", "rates"), manualRates, {merge:true});
  rates = {...rates, ...manualRates};
  renderRates();
  renderAll();
  alert("השערים נשמרו בהצלחה. הוצאות שכבר נוספו לא ישתנו.");
};


async function persistActiveRates(newRates, statusText){
  rates = {...rates, ...newRates};
  await trackedSetDoc(doc(db, "settings", "rates"), {
    ...rates,
    source: newRates.source || "עדכון אינטרנט",
    updatedAtText: newRates.updatedAtText || new Date().toLocaleString("he-IL"),
    updatedAt: Date.now()
  }, {merge:true});
  renderRates();
  renderAll();
}

window.updateRatesLive = async function(){
  try{
    document.getElementById("ratesStatus").innerText = "מעדכן שערים בזמן אמת...";
    const res = await fetch("https://open.er-api.com/v6/latest/ILS", {cache:"no-store"});
    const data = await res.json();

    if(data.result !== "success" || !data.rates || !data.rates.USD || !data.rates.JPY || !data.rates.EUR || !data.rates.GBP || !data.rates.CAD){
      throw new Error("Invalid rates response");
    }

    const usdIls = 1 / Number(data.rates.USD);
    const jpyIls = 1 / Number(data.rates.JPY);
    const eurIls = 1 / Number(data.rates.EUR);
    const gbpIls = 1 / Number(data.rates.GBP);
    const cadIls = 1 / Number(data.rates.CAD);

    const liveRates = {
      USD: usdIls,
      JPY: jpyIls,
      EUR: eurIls,
      GBP: gbpIls,
      CAD: cadIls,
      source: "שער חי מהאינטרנט",
      updatedAtText: new Date().toLocaleString("he-IL"),
      note: "שער חי דרך API ציבורי"
    };

    await trackedSetDoc(doc(db, "settings", "rates"), liveRates, {merge:true});
    rates = {...rates, ...liveRates};
    renderRates();
    renderAll();

    document.getElementById("ratesStatus").innerText = "השערים נשמרו. הוצאות קיימות נשארות לפי השער שבו הוזנו.";
    alert("השערים נשמרו בהצלחה. הוצאות שכבר נוספו לא השתנו.");
  }catch(err){
    console.error(err);
    document.getElementById("ratesStatus").innerText = "עדכון חי נכשל. נשארים עם השערים האחרונים.";
    alert("לא הצלחתי לעדכן שערים בזמן אמת. בדוק חיבור אינטרנט או נסה שוב.");
  }
};

let editingExpenseId = null;

function buildExpensePayload(existing = {}){
  const category = document.getElementById("category")?.value || "";
  const note = document.getElementById("note")?.value.trim() || "";
  const amount = Number(document.getElementById("amount")?.value);
  const currency = document.getElementById("currency")?.value || "ILS";
  const paymentMethod = document.getElementById("paymentMethod")?.value || "credit";
  const budgetOwner = document.getElementById("budgetOwner")?.value || "home";
  const date = expenseDateTextFromInput();

  if(!category || !amount || amount <= 0){
    alert("נא לבחור קטגוריה ולהכניס סכום תקין.");
    return null;
  }

  const rateSnapshot = {
    USD: Number(rates.USD),
    JPY: Number(rates.JPY),
    EUR: Number(rates.EUR),
    GBP: Number(rates.GBP),
    CAD: Number(rates.CAD),
    source: rates.source || "",
    updatedAtText: rates.updatedAtText || ""
  };

  const baseIlsAtEntry = convertToILS(amount, currency, rateSnapshot);
  const foreignCreditFeeILS = isForeignCreditExpense(currency, paymentMethod) ? baseIlsAtEntry * FOREIGN_CREDIT_FEE_RATE : 0;
  const ilsAtEntry = baseIlsAtEntry + foreignCreditFeeILS;

  return {
    ...existing,
    tripId: activeTripId,
    tripName: getActiveTrip().name || tripName || "",
    category,
    note,
    amount,
    currency,
    paymentMethod,
    budgetOwner,
    date,
    created: existing.created || Date.now(),
    updated: Date.now(),
    baseIlsAtEntry,
    foreignCreditFeeILS,
    foreignCreditFeeRateAtEntry: foreignCreditFeeILS > 0 ? FOREIGN_CREDIT_FEE_RATE : 0,
    ilsAtEntry,
    rateUSDAtEntry: rateSnapshot.USD,
    rateJPYAtEntry: rateSnapshot.JPY,
    rateEURAtEntry: rateSnapshot.EUR,
    rateGBPAtEntry: rateSnapshot.GBP,
    rateCADAtEntry: rateSnapshot.CAD,
    rateSourceAtEntry: rateSnapshot.source,
    rateUpdatedAtEntry: rateSnapshot.updatedAtText
  };
}

function resetExpenseForm(){
  editingExpenseId = null;
  const note = document.getElementById("note");
  const amount = document.getElementById("amount");
  const category = document.getElementById("category");
  const currency = document.getElementById("currency");
  const paymentMethod = document.getElementById("paymentMethod");
  const budgetOwner = document.getElementById("budgetOwner");
  const button = document.getElementById("expenseSubmitButton");
  const cancel = document.getElementById("expenseCancelEditButton");
  const title = document.getElementById("expenseFormTitle");

  if(note) note.value = "";
  if(amount) amount.value = "";
  if(category) category.selectedIndex = 0;
  if(currency) currency.value = "ILS";
  if(paymentMethod) paymentMethod.value = "credit";
  if(budgetOwner) budgetOwner.value = "home";
  ensureExpenseDateDefault();
  renderExpenseFeePreview();
  if(button) button.innerText = "הוסף הוצאה";
  if(cancel) cancel.style.display = "none";
  if(title) title.innerText = "➕ הוספת הוצאה";
}

window.cancelExpenseEdit = function(){
  resetExpenseForm();
};

window.startEditExpense = function(id){
  const e = expenses.find(x => x.id === id);
  if(!e) return;
  editingExpenseId = id;
  const category = document.getElementById("category");
  const note = document.getElementById("note");
  const amount = document.getElementById("amount");
  const currency = document.getElementById("currency");
  const paymentMethod = document.getElementById("paymentMethod");
  const budgetOwner = document.getElementById("budgetOwner");
  const button = document.getElementById("expenseSubmitButton");
  const cancel = document.getElementById("expenseCancelEditButton");
  const title = document.getElementById("expenseFormTitle");

  if(category) category.value = e.category || "";
  if(note) note.value = e.note || "";
  if(amount) amount.value = Number(e.amount || 0);
  if(currency) currency.value = e.currency || "ILS";
  if(paymentMethod) paymentMethod.value = e.paymentMethod || (Number(e.foreignCreditFeeILS || 0) > 0 ? "credit" : "cash");
  if(budgetOwner) budgetOwner.value = budgetOwnerKey(e);
  setExpenseDateInput(e.date);
  renderExpenseFeePreview();
  if(button) button.innerText = "שמירת הוצאה";
  if(cancel) cancel.style.display = "block";
  if(title) title.innerText = "✏️ עריכת הוצאה";
  document.getElementById("quickExpenseCard")?.scrollIntoView({behavior:"smooth", block:"start"});
};

window.addExpense = async function(){
  const existing = editingExpenseId ? (expenses.find(e => e.id === editingExpenseId) || {}) : {};
  const payload = buildExpensePayload(existing);
  if(!payload) return;

  if(editingExpenseId){
    await trackedSetDoc(doc(db, "expenses", editingExpenseId), payload, {merge:true});
  }else{
    await trackedAddDoc(collection(db, "expenses"), payload);
  }

  const category = payload.category;
  const date = payload.date;
  resetExpenseForm();
  setTimeout(() => checkWarnings(category, date), 800);
};

async function freezeLegacyExpensesOnce(){
  if(legacyFreezeRunning) return;
  legacyFreezeRunning = true;
  try{
    const snap = await getDocs(collection(db, "expenses"));
    const updates = [];
    snap.forEach(d => {
      const e = d.data();
      if(typeof e.ilsAtEntry !== "number" || !e.tripId){
        const rateSnapshot = {USD: Number(rates.USD), JPY: Number(rates.JPY), EUR: Number(rates.EUR), GBP: Number(rates.GBP), CAD: Number(rates.CAD)};
        updates.push(trackedSetDoc(doc(db, "expenses", d.id), {
          tripId: e.tripId || defaultTrip.id,
          tripName: e.tripName || "יפן 2026",
          ilsAtEntry: typeof e.ilsAtEntry === "number" ? e.ilsAtEntry : convertToILS(e.amount, e.currency, rateSnapshot),
          rateUSDAtEntry: rateSnapshot.USD,
          rateJPYAtEntry: rateSnapshot.JPY,
          rateEURAtEntry: rateSnapshot.EUR,
          rateGBPAtEntry: rateSnapshot.GBP,
          rateCADAtEntry: rateSnapshot.CAD,
          rateSourceAtEntry: "נעילה אוטומטית להוצאה ישנה",
          rateUpdatedAtEntry: new Date().toLocaleString("he-IL")
        }, {merge:true}));
      }
    });
    if(updates.length) await Promise.all(updates);
  }catch(err){
    console.error("legacy freeze failed", err);
  }finally{
    legacyFreezeRunning = false;
  }
}

window.deleteExpense = async function(id){
  if(confirm("למחוק את ההוצאה הזו?")){
    await trackedDeleteDoc(doc(db, "expenses", id));
  }
};

window.clearTrip = async function(){
  if(!confirm("לפני איפוס מומלץ לייצא PDF או HTML. למחוק את כל ההוצאות של הטיול הפעיל בלבד?")) return;
  const snap = await getDocs(collection(db, "expenses"));
  const deletes = [];
  snap.forEach(d => {
    const e = d.data();
    if((e.tripId || defaultTrip.id) === activeTripId){
      deletes.push(trackedDeleteDoc(doc(db, "expenses", d.id)));
    }
  });
  await Promise.all(deletes);
  alert("הטיול הפעיל אופס בהצלחה.");
};

function checkWarnings(category, date){
  const clothingTotal = activeExpenses().filter(e => budgetOwnerKey(e) === "home" && e.category === "ביגוד והנעלה")
    .reduce((s,e)=>s + expenseILS(e), 0);

  const foodTodayILS = activeExpenses().filter(e => budgetOwnerKey(e) === "home" && e.category === "אוכל" && e.date === date)
    .reduce((s,e)=>s + expenseILS(e), 0);

  const messages = [];

  if(category === "ביגוד והנעלה" && clothingTotal > getActiveClothingBudgetILS()){
    messages.push("חריגה מתקציב ביגוד והנעלה: " + fmtILS(clothingTotal) + " מתוך " + fmtILS(getActiveClothingBudgetILS()));
  }

  if(category === "אוכל" && foodTodayILS > getActiveFoodDailyBudgetILS()){
      messages.push("חריגה מתקציב אוכל יומי: " + fmtILS(foodTodayILS) + " מתוך " + fmtILS(getActiveFoodDailyBudgetILS()));
    }

  if(messages.length) alert(messages.join("\\n"));
}



function renderHomeTripSelector(){
  const homeSelect = document.getElementById("homeTripSelector");
  if(!homeSelect) return;

  const sorted = trips.slice().sort((a,b)=>(a.created||0)-(b.created||0));
  homeSelect.innerHTML = sorted.map(t => `<option value="${escapeHtml(t.id)}">${escapeHtml(t.name || t.id)}</option>`).join("");
  homeSelect.value = activeTripId;
}

window.switchTripFromHome = function(){
  const homeSelect = document.getElementById("homeTripSelector");
  if(!homeSelect) return;
  activeTripId = homeSelect.value || defaultTrip.id;
  localStorage.setItem("activeTripId", activeTripId);

  const mainSelect = document.getElementById("tripSelector");
  if(mainSelect) mainSelect.value = activeTripId;

  currentFilterType = "category";
  currentCategoryFilter = "ALL";
  currentDateFilter = "ALL";

  renderTripSelector();
  renderHomeTripSelector();
  renderAll();
};

function renderTripSelector(){
  const select = document.getElementById("tripSelector");
  if(!select) return;

  const sorted = trips.slice().sort((a,b)=>(a.created||0)-(b.created||0));
  select.innerHTML = sorted.map(t => `<option value="${escapeHtml(t.id)}">${escapeHtml(t.name || t.id)}</option>`).join("");

  if(!sorted.find(t => t.id === activeTripId)){
    activeTripId = "japan_2026";
    localStorage.setItem("activeTripId", activeTripId);
  }

  select.value = activeTripId;

  const trip = getActiveTrip();
  const tripNameInput = document.getElementById("tripName");
  if(tripNameInput) tripNameInput.value = trip.name || "";
  tripName = trip.name || "";

  const cfg = getTripBudgetConfig(trip);
  const clothingInput = document.getElementById("tripClothingInput");
  const foodInput = document.getElementById("tripFoodInput");
  const totalFoodInput = document.getElementById("tripTotalFoodInput");
  const idoBudgetInput = document.getElementById("tripIdoBudgetInput");
  const michaelBudgetInput = document.getElementById("tripMichaelBudgetInput");
  if(clothingInput) clothingInput.value = Number(cfg.shoppingBudget || 0);
  if(idoBudgetInput) idoBudgetInput.value = Number(cfg.idoPrivateBudget || 0);
  if(michaelBudgetInput) michaelBudgetInput.value = Number(cfg.michaelPrivateBudget || 0);
  if(foodInput) foodInput.value = Number(cfg.dailyFoodBudget || 0);
  if(totalFoodInput) totalFoodInput.value = Number(cfg.totalFoodBudget || 0);
  renderBudgetSourceRows();

  const activeLabel = document.getElementById("activeTripLabel");
  if(activeLabel){
    activeLabel.innerHTML = `טיול פעיל: <b>${escapeHtml(trip.name || activeTripId)}</b>`;
  }
  const topBudget = document.getElementById("topBudgetLabel");
  const topClothing = document.getElementById("topClothingBudgetLabel");
  const topFood = document.getElementById("topFoodBudgetLabel");
  if(topBudget) topBudget.innerText = fmtILS(getActiveBudgetILS());
  if(topClothing) topClothing.innerText = fmtILS(getActiveClothingBudgetILS());
  if(topFood) topFood.innerText = fmtILS(getActiveFoodDailyBudgetILS());
}

window.toggleTripSettings = function(forceOpen){
  const panel = document.getElementById("tripSettingsPanel");
  if(!panel) return;
  if(forceOpen === true){
    panel.classList.add("open");
  }else{
    panel.classList.toggle("open");
  }
};

window.switchTrip = function(){
  const select = document.getElementById("tripSelector");
  activeTripId = select?.value || defaultTrip.id;
  localStorage.setItem("activeTripId", activeTripId);
  currentFilterType = "category";
  currentCategoryFilter = "ALL";
  currentDateFilter = "ALL";
  budgetSourcesRenderedTripId = null;
  renderTripSelector();
  renderBudgetSourceRows(true);
  toggleTripSettings(true);
  renderAll();
};

window.createNewTrip = async function(){
  const name = prompt("שם הטיול החדש:");
  if(!name || !name.trim()) return;

  const id = safeTripId(name);
  const preset = getTripDefaultBudgetProfile({id, name:name.trim()});
  const newTrip = {
    id,
    name: name.trim(),
    budgetILS: preset.totalBudget,
    budgetSources: [{id:"source_" + Date.now(), amount:preset.totalBudget, currency:"ILS"}],
    idoPrivateBudgetILS: 0,
    michaelPrivateBudgetILS: 0,
    clothingBudgetILS: preset.shoppingBudget,
    foodDailyBudgetILS: preset.dailyFoodBudget,
    totalFoodBudgetILS: preset.totalFoodBudget || 0,
    created: Date.now()
  };

  await trackedSetDoc(doc(db, "trips", id), newTrip, {merge:true});
  trips = [...trips.filter(t => t.id !== id), newTrip].sort((a,b)=>(a.created||0)-(b.created||0));
  activeTripId = id;
  localStorage.setItem("activeTripId", activeTripId);
  renderTripSelector();
  renderHomeTripSelector();
  renderAll();
};

let budgetSourcesRenderedTripId = null;
function renderBudgetSourceRows(force = false){
  const box = document.getElementById("budgetSourcesRows");
  if(!box) return;
  if(!force && budgetSourcesRenderedTripId === activeTripId && box.children.length) { updateBudgetSourcesPreview(); return; }
  const trip = getActiveTrip();
  const sources = normalizeBudgetSources(trip);
  box.innerHTML = sources.map((src,index) => `
    <div class="budgetSourceRow" data-source-id="${escapeHtml(src.id)}">
      <input class="budgetSourceAmount" type="number" inputmode="decimal" min="0" step="0.01" value="${Number(src.amount || 0)}" oninput="renderBudgetSourcesPreview()" aria-label="סכום מקור תקציב">
      <select class="budgetSourceCurrency" onchange="renderBudgetSourcesPreview()" aria-label="מטבע מקור תקציב">
        ${["ILS","USD","JPY","EUR","GBP","CAD"].map(code => `<option value="${code}" ${src.currency===code?"selected":""}>${currencyLabel(code)}</option>`).join("")}
      </select>
      <button type="button" class="danger smallBtn budgetSourceRemove" onclick="removeBudgetSourceRow(this)" ${sources.length===1?"disabled":""}>הסר</button>
    </div>
  `).join("");
  budgetSourcesRenderedTripId = activeTripId;
  updateBudgetSourcesPreview();
}

window.addBudgetSourceRow = function(){
  const box = document.getElementById("budgetSourcesRows");
  if(!box) return;
  const row = document.createElement("div");
  row.className = "budgetSourceRow";
  row.dataset.sourceId = "source_" + Date.now() + "_" + Math.random().toString(36).slice(2,7);
  row.innerHTML = `
    <input class="budgetSourceAmount" type="number" inputmode="decimal" min="0" step="0.01" value="0" oninput="renderBudgetSourcesPreview()" aria-label="סכום מקור תקציב">
    <select class="budgetSourceCurrency" onchange="renderBudgetSourcesPreview()" aria-label="מטבע מקור תקציב">
      ${["ILS","USD","JPY","EUR","GBP","CAD"].map(code => `<option value="${code}">${currencyLabel(code)}</option>`).join("")}
    </select>
    <button type="button" class="danger smallBtn budgetSourceRemove" onclick="removeBudgetSourceRow(this)">הסר</button>`;
  box.appendChild(row);
  box.querySelectorAll(".budgetSourceRemove").forEach(b => b.disabled = false);
  updateBudgetSourcesPreview();
};

window.removeBudgetSourceRow = function(button){
  const box = document.getElementById("budgetSourcesRows");
  if(!box || box.children.length <= 1) return;
  button.closest(".budgetSourceRow")?.remove();
  if(box.children.length === 1) box.querySelector(".budgetSourceRemove").disabled = true;
  updateBudgetSourcesPreview();
};

function readBudgetSourcesFromUI(){
  return Array.from(document.querySelectorAll("#budgetSourcesRows .budgetSourceRow")).map((row,index) => ({
    id: row.dataset.sourceId || `source_${Date.now()}_${index}`,
    amount: cleanBudgetNumber(row.querySelector(".budgetSourceAmount")?.value, 0),
    currency: row.querySelector(".budgetSourceCurrency")?.value || "ILS"
  })).filter(src => src.amount > 0);
}

window.updateBudgetSourcesPreview = function(){
  const preview = document.getElementById("budgetSourcesPreview");
  if(!preview) return;
  const sources = readBudgetSourcesFromUI();
  const total = sources.reduce((sum,src) => sum + convertToILS(src.amount, src.currency, rates), 0);
  preview.innerHTML = sources.length
    ? `<b>שווי תקציב הבית כעת:</b> ${fmtILS(total)}<br><span class="small">השווי מתעדכן לפי שערי המטבע הפעילים.</span>`
    : `<span class="red">יש להזין לפחות מקור תקציב אחד עם סכום גדול מאפס.</span>`;
};

document.addEventListener("input", e => {
  if(e.target.matches(".budgetSourceAmount,.budgetSourceCurrency")) updateBudgetSourcesPreview();
});
document.addEventListener("change", e => {
  if(e.target.matches(".budgetSourceAmount,.budgetSourceCurrency")) updateBudgetSourcesPreview();
});

window.saveTripSettings = async function(){
  const trip = getActiveTrip();
  const name = document.getElementById("tripName")?.value.trim() || trip.name || "טיול ללא שם";
  const cfg = getTripBudgetConfig(trip);
  const budgetSources = readBudgetSourcesFromUI();
  if(!budgetSources.length){
    alert("יש להזין לפחות מקור תקציב אחד עם סכום גדול מאפס.");
    return;
  }
  const budget = budgetSources.reduce((sum,src) => sum + convertToILS(src.amount, src.currency, rates), 0);
  const idoPrivateBudget = cleanBudgetNumber(document.getElementById("tripIdoBudgetInput")?.value, cfg.idoPrivateBudget);
  const michaelPrivateBudget = cleanBudgetNumber(document.getElementById("tripMichaelBudgetInput")?.value, cfg.michaelPrivateBudget);
  const clothing = cleanBudgetNumber(document.getElementById("tripClothingInput")?.value, cfg.shoppingBudget);
  const food = cleanBudgetNumber(document.getElementById("tripFoodInput")?.value, cfg.dailyFoodBudget);
  const totalFood = cleanBudgetNumber(document.getElementById("tripTotalFoodInput")?.value, cfg.totalFoodBudget || 0);

  const updatedTrip = {
    ...trip,
    id: activeTripId,
    name,
    budgetILS: budget,
    budgetSources,
    idoPrivateBudgetILS: idoPrivateBudget,
    michaelPrivateBudgetILS: michaelPrivateBudget,
    clothingBudgetILS: clothing,
    foodDailyBudgetILS: food,
    totalFoodBudgetILS: totalFood
  };

  await trackedSetDoc(doc(db, "trips", activeTripId), updatedTrip, {merge:true});
  trips = trips.some(t => t.id === activeTripId)
    ? trips.map(t => t.id === activeTripId ? {...t, ...updatedTrip} : t)
    : [...trips, updatedTrip];
  budgetSourcesRenderedTripId = null;
  renderTripSelector();
  renderBudgetSourceRows(true);
  renderHomeTripSelector();
  renderAll();

  alert("הגדרות הטיול נשמרו בהצלחה.");
};

let compareTripsPanelOpen = false;

window.toggleCompareTripsPanel = function(){
  compareTripsPanelOpen = !compareTripsPanelOpen;
  const panel = document.getElementById("compareTripsPanel");
  if(panel){
    panel.classList.toggle("open", compareTripsPanelOpen);
  }
};

function getSelectedCompareTripIds(){
  const checked = Array.from(document.querySelectorAll(".compareTripCheck:checked")).map(i => i.value);
  if(checked.length) return checked.slice(0,5);
  return trips.slice(0, Math.min(2, trips.length)).map(t => t.id);
}

function getTripExpensesById(tripId){
  return expenses.filter(e => (e.tripId || defaultTrip.id) === tripId);
}

function getAllComparisonCategories(){
  const cats = new Set(fixedCategories);
  expenses.forEach(e => { if(e.category) cats.add(e.category); });
  return Array.from(cats).sort();
}

function getAllComparisonDates(){
  const dates = new Set();
  expenses.forEach(e => { if(e.date) dates.add(e.date); });
  return Array.from(dates).sort((a,b)=>dateSortKey(a).localeCompare(dateSortKey(b)));
}

function renderComparisonTripChecks(){
  const box = document.getElementById("compareTripsBox");
  if(!box) return;

  const existing = new Set(Array.from(document.querySelectorAll(".compareTripCheck:checked")).map(i => i.value));
  const sortedTrips = trips.slice().sort((a,b)=>(a.created||0)-(b.created||0));
  if(existing.size < 2){
    sortedTrips.forEach(t => {
      if(existing.size < 2) existing.add(t.id);
    });
  }

  box.innerHTML = sortedTrips.map(t => {
    const checked = existing.has(t.id) ? "checked" : "";
    return `<label class="tripCheckItem"><input class="compareTripCheck" type="checkbox" value="${escapeHtml(t.id)}" ${checked} onchange="handleCompareTripCheck(this)"> ${escapeHtml(t.name || t.id)}</label>`;
  }).join("");

  const panel = document.getElementById("compareTripsPanel");
  if(panel){
    panel.classList.toggle("open", compareTripsPanelOpen);
  }
}

window.handleCompareTripCheck = function(input){
  const checked = Array.from(document.querySelectorAll(".compareTripCheck:checked"));
  if(checked.length > 5){
    input.checked = false;
    alert("אפשר לבחור עד 5 טיולים להשוואה.");
    return;
  }
  renderTripComparison(false);
};

function renderCompareMetricOptions(){
  const metricSelect = document.getElementById("compareMetric");
  if(!metricSelect) return;

  const current = currentCompareMetric || metricSelect.value || "TOTAL";
  const cats = getAllComparisonCategories();

  metricSelect.innerHTML =
    `<option value="TOTAL">סה״כ הוצאות</option>` +
    `<option value="DATE">תאריך מסוים</option>` +
    `<option value="MOST_EXPENSIVE_DAY">יום הכי יקר</option>` +
    `<option value="CHEAPEST_DAY">יום הכי זול</option>` +
    cats.map(c => `<option value="CAT::${escapeHtml(c)}">${escapeHtml(c)}</option>`).join("");

  const validValues = ["TOTAL","DATE","MOST_EXPENSIVE_DAY","CHEAPEST_DAY", ...cats.map(c => "CAT::" + c)];
  currentCompareMetric = validValues.includes(current) ? current : "TOTAL";
  metricSelect.value = currentCompareMetric;
}

function renderCompareDateOptions(){
  const dateSelect = document.getElementById("compareDate");
  if(!dateSelect) return;

  const current = currentCompareDate || dateSelect.value || "ALL";
  const dates = getAllComparisonDates();
  dateSelect.innerHTML = `<option value="ALL">כל התאריכים יחד</option>` + dates.map(d => `<option value="${escapeHtml(d)}">${escapeHtml(d)}</option>`).join("");
  currentCompareDate = dates.includes(current) ? current : "ALL";
  dateSelect.value = currentCompareDate;
}

function renderCompareSelectors(){
  renderCompareMetricOptions();
  renderCompareDateOptions();

  const metric = document.getElementById("compareMetric")?.value || "TOTAL";
  const dateBox = document.getElementById("compareDateBox");
  if(dateBox) dateBox.style.display = metric === "DATE" ? "block" : "none";
}

function metricLabel(metric, date){
  if(metric === "TOTAL") return "סה״כ הוצאות";
  if(metric === "DATE") return date && date !== "ALL" ? "תאריך " + date : "כל התאריכים";
  if(metric === "MOST_EXPENSIVE_DAY") return "יום הכי יקר";
  if(metric === "CHEAPEST_DAY") return "יום הכי זול";
  if(metric.startsWith("CAT::")) return metric.replace("CAT::", "");
  return metric;
}

function tripMetricTotal(tripId, metric, date){
  let list = getTripExpensesById(tripId);

  if(metric === "DATE" && date !== "ALL"){
    list = list.filter(e => e.date === date);
  }

  if(metric.startsWith("CAT::")){
    const cat = metric.replace("CAT::", "");
    list = list.filter(e => e.category === cat);
  }

  if(metric === "MOST_EXPENSIVE_DAY" || metric === "CHEAPEST_DAY"){
    const byDate = {};
    list.forEach(e => {
      if(!e.date) return;
      byDate[e.date] = (byDate[e.date] || 0) + expenseILS(e);
    });
    const entries = Object.entries(byDate);
    if(!entries.length){
      return { total:0, count:0, extra:"אין נתונים" };
    }
    entries.sort((a,b) => metric === "MOST_EXPENSIVE_DAY" ? b[1]-a[1] : a[1]-b[1]);
    const [chosenDate, total] = entries[0];
    const count = list.filter(e => e.date === chosenDate).length;
    return { total, count, extra: chosenDate };
  }

  return {
    total: list.reduce((s,e)=>s + expenseILS(e), 0),
    count: list.length,
    extra: ""
  };
}


window.setCompareMetricFromUI = function(){
  const metricSelect = document.getElementById("compareMetric");
  currentCompareMetric = metricSelect?.value || "TOTAL";
  if(currentCompareMetric !== "DATE"){
    currentCompareDate = "ALL";
  }
  renderTripComparison(false);
};

window.setCompareDateFromUI = function(){
  const dateSelect = document.getElementById("compareDate");
  currentCompareDate = dateSelect?.value || "ALL";
  renderTripComparison(false);
};

function renderTripComparison(rebuildChecks = true){
  const head = document.getElementById("tripComparisonHead");
  const body = document.getElementById("tripComparisonBody");
  const status = document.getElementById("compareStatus");
  if(!head || !body) return;

  if(rebuildChecks) renderComparisonTripChecks();
  renderCompareSelectors();

  const selectedIds = getSelectedCompareTripIds();
  const selectedTrips = trips.filter(t => selectedIds.includes(t.id));
  const metric = currentCompareMetric || document.getElementById("compareMetric")?.value || "TOTAL";
  const date = currentCompareDate || document.getElementById("compareDate")?.value || "ALL";

  if(selectedTrips.length < 2){
    head.innerHTML = "";
    body.innerHTML = `<tr><td>בחר לפחות 2 טיולים להשוואה.</td></tr>`;
    if(status) status.innerHTML = `<span class="red">צריך לבחור לפחות 2 טיולים ועד 5.</span>`;
    return;
  }

  if(selectedTrips.length > 5){
    head.innerHTML = "";
    body.innerHTML = `<tr><td>אפשר לבחור עד 5 טיולים בלבד.</td></tr>`;
    if(status) status.innerHTML = `<span class="red">בחרת יותר מדי טיולים.</span>`;
    return;
  }

  const label = metricLabel(metric, date);
  if(status){
    status.innerHTML = `משווה: <b>${escapeHtml(label)}</b> בין <b>${selectedTrips.length}</b> טיולים.`;
  }

  if(metric === "MOST_EXPENSIVE_DAY" || metric === "CHEAPEST_DAY"){
    head.innerHTML = `<tr><th>טיול</th><th>${escapeHtml(label)}</th><th>תאריך</th><th>מס׳ הוצאות</th></tr>`;
    body.innerHTML = selectedTrips.map(t => {
      const result = tripMetricTotal(t.id, metric, date);
      return `
        <tr>
          <td><b>${escapeHtml(t.name || t.id)}</b></td>
          <td>${fmtILS(result.total)}</td>
          <td>${escapeHtml(result.extra || "")}</td>
          <td>${result.count}</td>
        </tr>
      `;
    }).join("");
    return;
  }

  head.innerHTML = `<tr><th>טיול</th><th>${escapeHtml(label)}</th><th>מס׳ הוצאות</th></tr>`;
  body.innerHTML = selectedTrips.map(t => {
    const result = tripMetricTotal(t.id, metric, date);
    return `
      <tr>
        <td><b>${escapeHtml(t.name || t.id)}</b></td>
        <td>${fmtILS(result.total)}</td>
        <td>${result.count}</td>
      </tr>
    `;
  }).join("");
}

function renderRates(){
  document.getElementById("usdRateTop").innerText = Number(rates.USD).toFixed(4);
  document.getElementById("jpyRateTop").innerText = Number(rates.JPY).toFixed(6);
  if(document.getElementById("jpy100RateTop")) document.getElementById("jpy100RateTop").innerText = (Number(rates.JPY) * 100).toFixed(4);
  if(document.getElementById("eurRateTop")) document.getElementById("eurRateTop").innerText = Number(rates.EUR).toFixed(4);
  if(document.getElementById("gbpRateTop")) document.getElementById("gbpRateTop").innerText = Number(rates.GBP).toFixed(4);
  if(document.getElementById("cadRateTop")) document.getElementById("cadRateTop").innerText = Number(rates.CAD).toFixed(4);
  document.getElementById("rateSource").innerText = rates.source || "";
  document.getElementById("rateUpdated").innerText = rates.updatedAtText || "";
  document.getElementById("usdRateInput").value = Number(rates.USD);
  document.getElementById("jpyRateInput").value = Number(rates.JPY);
  if(document.getElementById("eurRateInput")) document.getElementById("eurRateInput").value = Number(rates.EUR);
  if(document.getElementById("gbpRateInput")) document.getElementById("gbpRateInput").value = Number(rates.GBP);
  if(document.getElementById("cadRateInput")) document.getElementById("cadRateInput").value = Number(rates.CAD);
  renderExpenseFeePreview();
}

function getCategoryTotals(){
  const totals = {};
  activeExpenses().forEach(e => {
    totals[e.category] = (totals[e.category] || 0) + expenseILS(e);
  });
  return totals;
}

function getDailyTotals(){
  const days = {};
  activeExpenses().forEach(e => {
    if(!days[e.date]){
      days[e.date] = {
        total:0, food:0, transport:0, attractions:0, shopping:0, hotels:0,
        insurance:0, flights:0, carRental:0, fuel:0, other:0, categories:{}
      };
    }
    const ils = expenseILS(e);
    days[e.date].total += ils;
    days[e.date].categories[e.category] = (days[e.date].categories[e.category] || 0) + ils;
    if(e.category === "אוכל") days[e.date].food += ils;
    if(e.category === "תחבורה" || e.category === "תחבורה ציבורית") days[e.date].transport += ils;
    if(e.category === "אטרקציות") days[e.date].attractions += ils;
    if(e.category === "מלונות") days[e.date].hotels += ils;
    if(e.category === "ביטוח נסיעות") days[e.date].insurance += ils;
    if(e.category === "טיסות") days[e.date].flights += ils;
    if(e.category === "השכרת רכב") days[e.date].carRental += ils;
    if(e.category === "דלק") days[e.date].fuel += ils;
    if(["טיפים","כביסות",
  "קרוז",
  "שונות"].includes(e.category)) days[e.date].other += ils;
    if(["קניות עידו","קניות מיכאל","ביגוד והנעלה"].includes(e.category)) days[e.date].shopping += ils;
  });
  return days;
}

window.setSummaryCurrencyFromUI = function(){
  summaryCurrencyCode = document.getElementById("summaryCurrency")?.value || "ILS";
  renderSummary();
};

function renderSummary(){
  const totalILS = activeExpenses().reduce((s,e)=>s + expenseILS(e), 0);
  const homeSpentILS = getOwnerSpentILS("home");
  const idoSpentILS = getOwnerSpentILS("ido");
  const michaelSpentILS = getOwnerSpentILS("michael");
  const remainingILS = getActiveBudgetILS() - homeSpentILS;
  const totalsILS = getCategoryTotals();
  const clothingILS = totalsILS["ביגוד והנעלה"] || 0;

  const select = document.getElementById("summaryCurrency");
  const selectedCurrency = select ? select.value : summaryCurrencyCode;
  summaryCurrencyCode = selectedCurrency || "ILS";

  const totalDisplay = convertFromILS(totalILS, summaryCurrencyCode);
  const remainingDisplay = convertFromILS(remainingILS, summaryCurrencyCode);
  const clothingDisplay = convertFromILS(clothingILS, summaryCurrencyCode);
  const clothingBudgetDisplay = convertFromILS(getActiveClothingBudgetILS(), summaryCurrencyCode);

  let categoryHtml = "";
  Object.keys(totalsILS).sort().forEach(cat => {
    const totalCatILS = totalsILS[cat];
    const red = cat === "ביגוד והנעלה" && totalCatILS > getActiveClothingBudgetILS();
    const converted = convertFromILS(totalCatILS, summaryCurrencyCode);
    categoryHtml += `<div class="${red ? "red" : ""}">${escapeHtml(cat)}: <b>${fmtCurrencyByCode(converted, summaryCurrencyCode)}</b></div>`;
  });

  const box = document.getElementById("summaryFinal");
  if(!box) return;

  box.innerHTML = `
    <b>מטבע תצוגה:</b> ${currencyLabel(summaryCurrencyCode)}<br><br>
    <b>סה״כ הוצאות בכל התקציבים:</b> ${fmtCurrencyByCode(totalDisplay, summaryCurrencyCode)}<br>
    <b>הוצאות מתקציב הבית:</b> ${fmtCurrencyByCode(convertFromILS(homeSpentILS, summaryCurrencyCode), summaryCurrencyCode)}<br>
    <b>יתרת תקציב הבית:</b> <span class="${remainingILS < 0 ? "red" : "green"}">${fmtCurrencyByCode(remainingDisplay, summaryCurrencyCode)}</span><br><br>

    <b>תקציבים פרטיים:</b><br>
    עידו — נוצל ${fmtCurrencyByCode(convertFromILS(idoSpentILS, summaryCurrencyCode), summaryCurrencyCode)} מתוך ${fmtCurrencyByCode(convertFromILS(getOwnerBudgetILS("ido"), summaryCurrencyCode), summaryCurrencyCode)}; יתרה ${fmtCurrencyByCode(convertFromILS(getOwnerBudgetILS("ido")-idoSpentILS, summaryCurrencyCode), summaryCurrencyCode)}<br>
    מיכאל — נוצל ${fmtCurrencyByCode(convertFromILS(michaelSpentILS, summaryCurrencyCode), summaryCurrencyCode)} מתוך ${fmtCurrencyByCode(convertFromILS(getOwnerBudgetILS("michael"), summaryCurrencyCode), summaryCurrencyCode)}; יתרה ${fmtCurrencyByCode(convertFromILS(getOwnerBudgetILS("michael")-michaelSpentILS, summaryCurrencyCode), summaryCurrencyCode)}<br><br>

    <b>בקרת ביגוד, הנעלה, ואלקטרוניקה:</b><br>
    נוצל: <span class="${clothingILS > getActiveClothingBudgetILS() ? "red" : ""}">${fmtCurrencyByCode(clothingDisplay, summaryCurrencyCode)}</span>
    מתוך ${fmtCurrencyByCode(clothingBudgetDisplay, summaryCurrencyCode)}<br><br>

    <b>סיכום לפי קטגוריות:</b><br>
    ${categoryHtml || "אין עדיין הוצאות"}
  `;
}

function renderDaily(){
  const tbody = document.getElementById("dailyBody");
  const thead = document.querySelector("#dailyTable thead");
  tbody.innerHTML = "";
  const days = getDailyTotals();
  const keys = Object.keys(days).sort((a,b)=>dateSortKey(a).localeCompare(dateSortKey(b)));
  const usedCats = Array.from(new Set(activeExpenses().map(e => e.category))).sort();

  if(thead){
    thead.innerHTML = `<tr><th>תאריך</th><th>סה״כ יומי</th>${usedCats.map(c => `<th>${escapeHtml(c)}</th>`).join("")}</tr>`;
  }

  if(!keys.length){
    tbody.innerHTML = `<tr><td colspan="2">אין עדיין הוצאות</td></tr>`;
    return;
  }

  keys.forEach(date => {
    const d = days[date];
    tbody.innerHTML += `
      <tr>
        <td>${date}</td>
        <td><b>${fmtILS(d.total)}</b></td>
        ${usedCats.map(cat => {
          const val = d.categories[cat] || 0;
          const cls = cat === "אוכל" && val > getActiveFoodDailyBudgetILS() ? "red-cell" : "";
          return `<td class="${cls}">${val ? fmtILS(val) : "—"}</td>`;
        }).join("")}
      </tr>
    `;
  });
}


function compactDateForTable(dateText){
  const s = String(dateText || "");
  const m = s.match(/^(\d{1,2})[./-](\d{1,2})[./-](\d{2,4})$/);
  if(!m) return s;
  return `${m[1]}.${m[2]}`;
}
function compactCurrencyLabel(currency){
  if(currency === "ILS") return "₪";
  if(currency === "USD") return "$";
  if(currency === "JPY") return "¥";
  if(currency === "EUR") return "€";
  if(currency === "GBP") return "£";
  if(currency === "CAD") return "C$";
  return currency || "";
}
function compactRateLabel(e){
  if(e.currency === "ILS") return "שקל";
  if(e.currency === "USD") return Number(e.rateUSDAtEntry || rates.USD).toFixed(2);
  if(e.currency === "JPY") return Number(e.rateJPYAtEntry || rates.JPY).toFixed(4);
  if(e.currency === "EUR") return Number(e.rateEURAtEntry || rates.EUR).toFixed(2);
  if(e.currency === "GBP") return Number(e.rateGBPAtEntry || rates.GBP).toFixed(2);
  if(e.currency === "CAD") return Number(e.rateCADAtEntry || rates.CAD).toFixed(2);
  return "";
}


function refreshDynamicExpensesTableWidth(){
  const table = document.getElementById("expensesTable");
  if(!table) return;
  table.style.width = "auto";
  requestAnimationFrame(() => {
    table.style.width = "max-content";
  });
}

function renderExpenses(){
  const tbody = document.getElementById("expensesBody");
  if(!tbody) return;
  tbody.innerHTML = "";

  updateFilterOptions();
  renderCategoryTotals();

    const list = visibleExpenses()
    .slice()
    .sort((a,b)=> dateSortKey(a.date).localeCompare(dateSortKey(b.date)) || (a.created||0)-(b.created||0));

  if(!list.length){
    const desc = activeFilterDescription();
    tbody.innerHTML = `<tr><td colspan="9">אין הוצאות להצגה לפי הסינון הנוכחי</td></tr>`;
    const summary = document.getElementById("selectedCategorySummary");
    if(summary) summary.innerHTML = `אין הוצאות להצגה — ${escapeHtml(desc)}.`;
    refreshDynamicExpensesTableWidth();
    return;
  }

  let total = 0;

  list.forEach(e => {
    const ils = expenseILS(e);
    total += ils;
    const rateText = e.currency === "USD" ? "USD " + Number(e.rateUSDAtEntry || rates.USD).toFixed(4) :
      e.currency === "JPY" ? "JPY " + Number(e.rateJPYAtEntry || rates.JPY).toFixed(6) :
      e.currency === "EUR" ? "EUR " + Number(e.rateEURAtEntry || rates.EUR).toFixed(4) :
      e.currency === "GBP" ? "GBP " + Number(e.rateGBPAtEntry || rates.GBP).toFixed(4) :
      e.currency === "CAD" ? "CAD " + Number(e.rateCADAtEntry || rates.CAD).toFixed(4) :
      "שקל";
    tbody.innerHTML += `
      <tr>
        <td>${compactDateForTable(e.date)}</td>
        <td>${escapeHtml(budgetOwnerLabel(budgetOwnerKey(e)))}</td>
        <td>${escapeHtml(e.category)}</td>
        <td>${escapeHtml(e.note || "")}</td>
        <td>${Number(e.amount).toFixed(2)}</td>
        <td>${compactCurrencyLabel(e.currency)}<br><span class="expenseSubLine">${paymentMethodLabel(e.paymentMethod || (Number(e.foreignCreditFeeILS || 0) > 0 ? "credit" : "cash"))}</span></td>
        <td>${formatExpenseTotalCell(e)}</td>
        <td>${compactRateLabel(e)}</td>
        <td>
          <div class="rowActions">
            <button class="secondaryBtn smallBtn" onclick="startEditExpense('${e.id}')">ערוך</button>
            <button class="danger smallBtn" onclick="deleteExpense('${e.id}')">×</button>
          </div>
        </td>
      </tr>
    `;
  });

  tbody.innerHTML += `
    <tr>
      <td colspan="6"><b>סה״כ כל ההוצאות המוצגות</b></td>
      <td><b>${fmtILS(typeof total !== "undefined" ? total : filteredTotal)}</b></td>
      <td colspan="2"></td>
    </tr>
  `;

  const summary = document.getElementById("selectedCategorySummary");
  if(summary){
    const desc = activeFilterDescription();
    const totalActive = activeExpenses().reduce((s,e)=>s + expenseILS(e), 0);
    if(desc === "כל ההוצאות בטיול הפעיל"){
      summary.innerHTML = `סה״כ הוצאות בטיול הפעיל: <b>${fmtILS(total)}</b>`;
    }else{
      summary.innerHTML = `סה״כ מוצג לפי ${escapeHtml(desc)}: <b>${fmtILS(total)}</b><br><span class="small">סה״כ כל הטיול הפעיל: ${fmtILS(totalActive)}</span>`;
    }
  }

  if(typeof applyMobileTableLabels === "function"){
    setTimeout(applyMobileTableLabels, 30);
  }
  refreshDynamicExpensesTableWidth();
}

function updateFilterOptions(){
  updateCategoryFilterOptions();
  updateDateFilterOptions();

  const typeSelect = document.getElementById("filterType");
  if(typeSelect) typeSelect.value = currentFilterType;

  const catBox = document.getElementById("categoryFilterBox");
  const dateBox = document.getElementById("dateFilterBox");
  if(catBox) catBox.style.display = currentFilterType === "category" ? "block" : "none";
  if(dateBox) dateBox.style.display = currentFilterType === "date" ? "block" : "none";
}

function updateCategoryFilterOptions(){
  const select = document.getElementById("categoryFilter");
  if(!select) return;
  const fromExpenses = Array.from(new Set(activeExpenses().map(e => e.category))).filter(Boolean);
  const cats = Array.from(new Set([...fixedCategories, ...fromExpenses])).sort();

  select.innerHTML = `<option value="ALL">כל הקטגוריות</option>` + cats.map(c => `<option value="${escapeHtml(c)}">${escapeHtml(c)}</option>`).join("");

  if(currentCategoryFilter !== "ALL" && !cats.includes(currentCategoryFilter)){
    currentCategoryFilter = "ALL";
  }
  select.value = currentCategoryFilter;
}

function updateDateFilterOptions(){
  const select = document.getElementById("dateFilter");
  const chips = document.getElementById("activeDatesChips");
  if(!select) return;

  const dates = Array.from(new Set(activeExpenses().map(e => e.date).filter(Boolean))).sort((a,b)=>dateSortKey(a).localeCompare(dateSortKey(b)));

  select.innerHTML = `<option value="ALL">כל התאריכים הפעילים</option>` + dates.map(d => `<option value="${escapeHtml(d)}">${escapeHtml(d)}</option>`).join("");

  if(currentDateFilter !== "ALL" && !dates.includes(currentDateFilter)){
    currentDateFilter = "ALL";
  }
  select.value = currentDateFilter;

  if(chips){
    if(!dates.length){
      chips.innerHTML = `<span class="small">אין עדיין תאריכים עם פעילות.</span>`;
    }else{
      chips.innerHTML = dates.map(d => `<button class="dateChip ${currentDateFilter === d ? "active" : ""}" onclick="selectDateFilter('${escapeHtml(d)}')">${escapeHtml(d)}</button>`).join("");
    }
  }
}

window.setFilterTypeFromUI = function(){
  const type = document.getElementById("filterType")?.value || "category";
  currentFilterType = type;
  renderAll();
};

window.setCategoryFilterFromUI = function(){
  const val = document.getElementById("categoryFilter")?.value || "ALL";
  currentFilterType = "category";
  currentCategoryFilter = val;
  renderAll();
};

window.setDateFilterFromUI = function(){
  const val = document.getElementById("dateFilter")?.value || "ALL";
  currentFilterType = "date";
  currentDateFilter = val;
  renderAll();
};

window.selectDateFilter = function(dateValue){
  currentFilterType = "date";
  currentDateFilter = dateValue;
  renderAll();
};

window.onFilterTypeChange = function(){
  currentFilterType = document.getElementById("filterType")?.value || "category";
  renderAll();
};

window.clearCategoryFilter = function(){
  currentFilterType = "category";
  currentCategoryFilter = "ALL";
  currentDateFilter = "ALL";
  renderAll();
};

function renderCategoryTotals(){
  const box = document.getElementById("categoryTotalsGrid");
  if(!box) return;
  const totals = getCategoryTotals();
  const entries = Object.entries(totals).sort((a,b)=>b[1]-a[1]);
  if(!entries.length){
    box.innerHTML = `<div class="categoryTotalItem">אין עדיין הוצאות</div>`;
    return;
  }
  box.innerHTML = entries.map(([cat,total]) => `
    <div class="categoryTotalItem">
      ${escapeHtml(cat)}<br>
      <span>${fmtILS(total)}</span>
    </div>
  `).join("");
}

window.toggleTheme = function(){
  document.body.classList.toggle("darkMode");
  localStorage.setItem("budgetTheme", document.body.classList.contains("darkMode") ? "dark" : "light");
};

function applySavedTheme(){
  if(localStorage.getItem("budgetTheme") === "dark"){
    document.body.classList.add("darkMode");
  }
}


const chartPalette = [
  "#2563eb","#16a34a","#f59e0b","#dc2626","#7c3aed","#0891b2",
  "#db2777","#65a30d","#ea580c","#475569","#0f766e","#9333ea",
  "#b45309","#1d4ed8","#be123c","#4d7c0f"
];

function setStatusClass(el, status){
  if(!el) return;
  el.classList.remove("statusGood","statusWarn","statusBad");
  if(status === "bad") el.classList.add("statusBad");
  else if(status === "warn") el.classList.add("statusWarn");
  else el.classList.add("statusGood");
}

function getStatusByPercent(percent){
  if(percent >= 100) return "bad";
  if(percent >= 80) return "warn";
  return "good";
}

function drawEmptyCanvas(canvas, text){
  if(!canvas) return;
  const ctx = canvas.getContext("2d");
  ctx.clearRect(0,0,canvas.width,canvas.height);
  ctx.fillStyle = "#64748b";
  ctx.font = "18px Arial";
  ctx.textAlign = "center";
  ctx.fillText(text, canvas.width/2, canvas.height/2);
}

function drawPieChart(totals){
  const canvas = document.getElementById("categoryPie");
  const legend = document.getElementById("categoryLegend");
  if(!canvas || !legend) return;

  const entries = Object.entries(totals).filter(([k,v]) => v > 0).sort((a,b)=>b[1]-a[1]);
  const sum = entries.reduce((s,[k,v])=>s+v,0);
  const ctx = canvas.getContext("2d");
  ctx.clearRect(0,0,canvas.width,canvas.height);
  legend.innerHTML = "";

  if(!entries.length || sum <= 0){
    drawEmptyCanvas(canvas, "אין עדיין נתונים לגרף");
    return;
  }

  const cx = canvas.width / 2;
  const cy = canvas.height / 2;
  const radius = Math.min(canvas.width, canvas.height) * 0.34;
  let start = -Math.PI / 2;

  entries.forEach(([cat,val], i) => {
    const slice = (val / sum) * Math.PI * 2;
    ctx.beginPath();
    ctx.moveTo(cx, cy);
    ctx.arc(cx, cy, radius, start, start + slice);
    ctx.closePath();
    ctx.fillStyle = chartPalette[i % chartPalette.length];
    ctx.fill();
    start += slice;
  });

  entries.slice(0,10).forEach(([cat,val], i) => {
    const pct = ((val/sum)*100).toFixed(1);
    const div = document.createElement("div");
    div.className = "legendItem";
    div.innerHTML = `<span class="legendColor" style="background:${chartPalette[i % chartPalette.length]}"></span>
      <span>${escapeHtml(cat)} — ${fmtILS(val)} (${pct}%)</span>`;
    legend.appendChild(div);
  });
}

function drawDailyBarChart(days){
  const canvas = document.getElementById("dailyBar");
  if(!canvas) return;
  const ctx = canvas.getContext("2d");
  ctx.clearRect(0,0,canvas.width,canvas.height);

  const entries = Object.keys(days).sort((a,b)=>dateSortKey(a).localeCompare(dateSortKey(b))).map(d => [d, days[d].total]);
  if(!entries.length){
    drawEmptyCanvas(canvas, "אין עדיין נתונים לגרף");
    return;
  }

  const padding = 38;
  const chartW = canvas.width - padding * 2;
  const chartH = canvas.height - padding * 2;
  const maxVal = Math.max(...entries.map(e=>e[1]), 1);
  const barW = Math.max(8, chartW / entries.length * 0.65);
  const gap = chartW / entries.length;

  ctx.strokeStyle = "#cbd5e1";
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(padding, padding);
  ctx.lineTo(padding, padding + chartH);
  ctx.lineTo(padding + chartW, padding + chartH);
  ctx.stroke();

  entries.forEach(([date,val], i) => {
    const h = (val / maxVal) * chartH;
    const x = padding + i * gap + (gap - barW)/2;
    const y = padding + chartH - h;
    ctx.fillStyle = val >= 3000 ? "#dc2626" : val >= 2000 ? "#f59e0b" : "#16a34a";
    ctx.fillRect(x, y, barW, h);
  });

  ctx.fillStyle = "#334155";
  ctx.font = "13px Arial";
  ctx.textAlign = "center";
  ctx.fillText("שיא יומי: " + fmtILS(maxVal), canvas.width/2, 20);
}

function renderDashboard(){
  const totalILS = activeExpenses().reduce((s,e)=>s + expenseILS(e), 0);
  const homeSpentILS = getOwnerSpentILS("home");
  const remaining = getActiveBudgetILS() - homeSpentILS;
  const percent = getActiveBudgetILS() > 0 ? (homeSpentILS / getActiveBudgetILS()) * 100 : 0;
  const status = getStatusByPercent(percent);
  const days = getDailyTotals();
  const totals = getCategoryTotals();
  const today = todayText();
  const todayTotal = days[today]?.total || 0;
  const foodTodayILS = days[today]?.food || 0;
  const foodTodayILSDisplay = foodTodayILS;
  const clothing = totals["ביגוד והנעלה"] || 0;
  const activeDays = Object.keys(days).length || 1;
  const avgDaily = totalILS / activeDays;

  const elTotal = document.getElementById("dashTotal");
  const elRemaining = document.getElementById("dashRemaining");
  const elPercent = document.getElementById("dashPercent");
  const elAvg = document.getElementById("dashAvgDaily");
  const elToday = document.getElementById("dashToday");
  const elFood = document.getElementById("dashFoodToday");
  const elClothing = document.getElementById("dashClothing");
  const elCount = document.getElementById("dashCount");
  const bar = document.getElementById("budgetProgressBar");
  const statusText = document.getElementById("budgetStatusText");

  if(elTotal) elTotal.innerText = fmtILS(totalILS);
  if(elRemaining) elRemaining.innerText = fmtILS(remaining);
  if(elPercent) elPercent.innerText = percent.toFixed(1) + "%";
  if(elAvg) elAvg.innerText = fmtILS(avgDaily);
  if(elToday) elToday.innerText = fmtILS(todayTotal);
  if(elFood) elFood.innerText = fmtILS(foodTodayILSDisplay);
  if(elClothing) elClothing.innerText = fmtILS(clothing);
  if(elCount) elCount.innerText = String(activeExpenses().length);

  setStatusClass(elRemaining, remaining < 0 ? "bad" : status);
  setStatusClass(elPercent, status);
  setStatusClass(elFood, foodTodayILSDisplay > getActiveFoodDailyBudgetILS() ? "bad" : foodTodayILSDisplay >= getActiveFoodDailyBudgetILS()*0.8 ? "warn" : "good");
  setStatusClass(elClothing, clothing > getActiveClothingBudgetILS() ? "bad" : clothing >= getActiveClothingBudgetILS()*0.8 ? "warn" : "good");

  if(bar){
    const capped = Math.min(percent, 100);
    bar.style.width = capped.toFixed(1) + "%";
    bar.style.background = status === "bad" ? "#dc2626" : status === "warn" ? "#f59e0b" : "#16a34a";
  }

  if(statusText){
    if(percent >= 100){
      statusText.innerHTML = `<span class="statusBad"><b>חריגה:</b> עברתם את התקציב הכולל ב־${fmtILS(Math.abs(remaining))}.</span>`;
    }else if(percent >= 80){
      statusText.innerHTML = `<span class="statusWarn"><b>התראה:</b> ניצלתם ${percent.toFixed(1)}% מהתקציב. כדאי להאט קצב.</span>`;
    }else{
      statusText.innerHTML = `<span class="statusGood"><b>תקין:</b> אתם עדיין בטווח התקציב.</span>`;
    }
  }

  drawPieChart(totals);
  drawDailyBarChart(days);
}



function renderTripBudgetSummary(){
  const box = document.getElementById("tripBudgetSummaryBox");
  if(!box) return;

  const cfg = getCurrentTripBudgetConfig();
  const activeTrip = trips.find(t => t.id === activeTripId) || {};
  const activeTripName = activeTrip.name || activeTripId || "טיול פעיל";
  const totalSpent = getOwnerSpentILS("home", activeTripId);
  const idoSpent = getOwnerSpentILS("ido", activeTripId);
  const michaelSpent = getOwnerSpentILS("michael", activeTripId);
  const shoppingSpent = getTripShoppingILS(activeTripId);

  const totalLeft = cfg.totalBudget - totalSpent;
  const shoppingLeft = cfg.shoppingBudget - shoppingSpent;

  function cls(v){
    if(v < 0) return "tripBudgetBad";
    if(v < (cfg.totalBudget * 0.15)) return "tripBudgetWarn";
    return "tripBudgetGood";
  }

  box.innerHTML = `
    <div class="tripBudgetSub" style="margin-bottom:12px;font-weight:800;">טיול פעיל: ${escapeHtml(activeTripName)}</div>
    <div class="tripBudgetSummaryGrid">
      <div class="tripBudgetCard">
        <h4>💰 תקציב כולל לטיול</h4>
        <div class="tripBudgetMain ${cls(totalLeft)}">${fmtILS(totalLeft)}</div>
        <div class="tripBudgetSub">
          תקציב כולל: ${fmtILS(cfg.totalBudget)}<br>
          נוצל עד עכשיו: ${fmtILS(totalSpent)}
        </div>
      </div>

      <div class="tripBudgetCard">
        <h4>👦 תקציב עידו פרטי</h4>
        <div class="tripBudgetMain ${cfg.idoPrivateBudget-idoSpent < 0 ? "tripBudgetBad" : "tripBudgetGood"}">${fmtILS(cfg.idoPrivateBudget-idoSpent)}</div>
        <div class="tripBudgetSub">תקציב: ${fmtILS(cfg.idoPrivateBudget)}<br>נוצל: ${fmtILS(idoSpent)}</div>
      </div>

      <div class="tripBudgetCard">
        <h4>👦 תקציב מיכאל פרטי</h4>
        <div class="tripBudgetMain ${cfg.michaelPrivateBudget-michaelSpent < 0 ? "tripBudgetBad" : "tripBudgetGood"}">${fmtILS(cfg.michaelPrivateBudget-michaelSpent)}</div>
        <div class="tripBudgetSub">תקציב: ${fmtILS(cfg.michaelPrivateBudget)}<br>נוצל: ${fmtILS(michaelSpent)}</div>
      </div>

      <div class="tripBudgetCard">
        <h4>🛍️ תקציב קניות</h4>
        <div class="tripBudgetMain ${shoppingLeft < 0 ? "tripBudgetBad" : "tripBudgetGood"}">${fmtILS(shoppingLeft)}</div>
        <div class="tripBudgetSub">
          תקציב קניות: ${fmtILS(cfg.shoppingBudget)}<br>
          נוצל בקניות: ${fmtILS(shoppingSpent)}
        </div>
      </div>

      <div class="tripBudgetCard">
        <h4>🍽️ תקציב אוכל</h4>
        <div class="tripBudgetMain tripBudgetGood">${fmtILS(cfg.dailyFoodBudget)}</div>
        <div class="tripBudgetSub">
          יעד יומי: ${fmtILS(cfg.dailyFoodBudget)}<br>
          ${cfg.totalFoodBudget ? "מסגרת אוכל כוללת: " + fmtILS(cfg.totalFoodBudget) : "ללא מסגרת אוכל כוללת"}
        </div>
      </div>
    </div>
  `;
}



function applyMobileTableLabels(){
  document.querySelectorAll("table.mobileCards").forEach(table => {
    const headers = Array.from(table.querySelectorAll("thead th")).map(th => th.innerText.trim());
    table.querySelectorAll("tbody tr").forEach(tr => {
      Array.from(tr.children).forEach((td, i) => {
        if(headers[i]) td.setAttribute("data-label", headers[i]);
      });
    });
  });
}


function renderHomeSummary(){
  const trip = trips.find(t => t.id === activeTripId) || {};
  const cfg = getCurrentTripBudgetConfig ? getCurrentTripBudgetConfig() : {totalBudget:0,shoppingBudget:0,dailyFoodBudget:0};
  const totalSpent = getOwnerSpentILS ? getOwnerSpentILS("home", activeTripId) : 0;
  const shoppingSpent = getTripShoppingILS ? getTripShoppingILS(activeTripId) : 0;
  const totalLeft = Number(cfg.totalBudget || 0) - totalSpent;
  const shoppingLeft = Number(cfg.shoppingBudget || 0) - shoppingSpent;

  const set = (id, value) => {
    const el = document.getElementById(id);
    if(el) el.innerText = value;
  };

  set("homeTripName", trip.name || activeTripId || "—");
  set("homeTotalLeft", fmtILS(totalLeft));
  set("homeTotalUsed", "נוצל: " + fmtILS(totalSpent) + " מתוך " + fmtILS(cfg.totalBudget || 0));
  set("homeShoppingLeft", fmtILS(shoppingLeft));
  set("homeShoppingUsed", "נוצל בקניות: " + fmtILS(shoppingSpent) + " מתוך " + fmtILS(cfg.shoppingBudget || 0));
  set("homeFoodBudget", fmtILS(cfg.dailyFoodBudget || 0));
  set("homeFoodSub", cfg.totalFoodBudget ? "מסגרת אוכל כוללת: " + fmtILS(cfg.totalFoodBudget) : "יעד יומי פעיל");

  const totalEl = document.getElementById("homeTotalLeft");
  const shopEl = document.getElementById("homeShoppingLeft");
  if(totalEl) totalEl.style.color = totalLeft < 0 ? "#dc2626" : "#15803d";
  if(shopEl) shopEl.style.color = shoppingLeft < 0 ? "#dc2626" : "#15803d";
}

function renderAll(){
  ensureExpenseDateDefault();
  renderTripSelector();
  renderRates();
  renderSummary();
  renderDaily();
  renderExpenses();
  renderDashboard();
  renderTripBudgetSummary();
  renderHomeSummary();
  renderHomeTripSelector();
  setTimeout(applyMobileTableLabels, 50);
  if(typeof initAppTabs === 'function') setTimeout(initAppTabs, 80);
  renderTripComparison();
}


window.exportHTML = function(){
  try{
    const generated = new Date().toLocaleString("he-IL");
    const activeTripTitle = getActiveTrip().name || tripName || "חופשה";

    const expensesRows = activeExpenses().map(e => `
      <tr>
        <td>${compactDateForTable(e.date)}</td>
        <td>${escapeHtml(budgetOwnerLabel(budgetOwnerKey(e)))}</td>
        <td>${escapeHtml(e.category)}</td>
        <td>${escapeHtml(e.note || "")}</td>
        <td>${Number(e.amount).toFixed(2)}</td>
        <td>${compactCurrencyLabel(e.currency)} / ${paymentMethodLabel(e.paymentMethod || (Number(e.foreignCreditFeeILS || 0) > 0 ? "credit" : "cash"))}</td>
        <td>${formatExpenseTotalCell(e)}</td>
        <td>${compactRateLabel(e)}</td>
      </tr>
    `).join("");

    const report = `<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>דוח תקציב ${escapeHtml(activeTripTitle)}</title>
<style>
body{font-family:Arial,"Noto Sans Hebrew",sans-serif;direction:rtl;padding:20px;color:#111827;background:#fff}
h1,h2{text-align:center}
.meta{text-align:center;color:#475569;margin-bottom:18px}
.summary{border:1px solid #d7dce5;border-radius:14px;padding:14px;margin:14px 0;line-height:1.8}
table{width:100%;border-collapse:collapse;margin-top:14px;font-size:12px}
th,td{border:1px solid #d7dce5;padding:8px;text-align:center;vertical-align:middle}
th{background:#0b84f3;color:white}
tr:nth-child(even) td{background:#fafafa}
</style>
</head>
<body>
<h1>דוח תקציב חופשה</h1>
<h2>${escapeHtml(activeTripTitle)}</h2>
<div class="meta">נוצר: ${generated}</div>
<div class="summary">${document.getElementById("summaryFinal")?.innerHTML || ""}</div>
<h2>סיכום יומי</h2>
${document.getElementById("dailyTable")?.outerHTML || ""}
<h2>פירוט הוצאות</h2>
<table>
<thead><tr><th>תאריך</th><th>תקציב</th><th>קטגוריה</th><th>פירוט</th><th>סכום</th><th>מטבע/תשלום</th><th>סה״כ בשקלים</th><th>שער</th></tr></thead>
<tbody>${expensesRows || `<tr><td colspan="8">אין הוצאות להצגה</td></tr>`}</tbody>
</table>
</body>
</html>`;

    const blob = new Blob([report], {type:"text/html;charset=utf-8"});
    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.download = "דוח_תקציב_" + activeTripTitle + ".html";
    document.body.appendChild(a);
    a.click();
    a.remove();
  }catch(err){
    console.error("exportHTML failed", err);
    alert("ייצוא HTML נכשל. רענן את האפליקציה ונסה שוב.");
  }
};






function buildPrintableBudgetReport(){
  const activeTripTitle = getActiveTrip().name || tripName || "חופשה";
  const generated = new Date().toLocaleString("he-IL");

  const rows = activeExpenses().map(e => `
    <tr>
      <td>${compactDateForTable(e.date)}</td>
      <td>${escapeHtml(e.category)}</td>
      <td>${escapeHtml(e.note || "")}</td>
      <td>${Number(e.amount).toFixed(2)}</td>
      <td>${compactCurrencyLabel(e.currency)} / ${paymentMethodLabel(e.paymentMethod || (Number(e.foreignCreditFeeILS || 0) > 0 ? "credit" : "cash"))}</td>
      <td>${formatExpenseTotalCell(e)}</td>
      <td>${compactRateLabel(e)}</td>
    </tr>
  `).join("");

  return `
<div class="printReport">
  <h1>דוח תקציב חופשה</h1>
  <h2>${escapeHtml(activeTripTitle)}</h2>
  <div class="meta">נוצר: ${generated}</div>
  <div class="summary">${document.getElementById("summaryFinal")?.innerHTML || ""}</div>
  <h2>פירוט הוצאות</h2>
  <table>
    <thead><tr><th>תאריך</th><th>תקציב</th><th>קטגוריה</th><th>פירוט</th><th>סכום</th><th>מטבע/תשלום</th><th>סה״כ בשקלים</th><th>שער</th></tr></thead>
    <tbody>${rows || `<tr><td colspan="8">אין הוצאות להצגה</td></tr>`}</tbody>
  </table>
</div>`;
}

window.closePdfPreview = function(){
  const overlay = document.getElementById("pdfPreviewOverlay");
  if(overlay) overlay.remove();
  const iframe = document.getElementById("pdfPrintFrame");
  if(iframe) iframe.remove();
  document.body.classList.remove("pdfPreviewOpen");
};


window.printPdfPreview = function(){
  try{
    const reportHtml = `<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>דוח תקציב</title>
<style>
html,body{background:#fff!important;color:#111827!important;margin:0}
body{font-family:Arial,"Noto Sans Hebrew",sans-serif;direction:rtl;padding:10mm}
h1,h2{text-align:center;margin:10px 0}
.meta{text-align:center;color:#475569;margin-bottom:18px}
.summary{border:1px solid #d7dce5;border-radius:14px;padding:14px;margin:14px 0;line-height:1.8}
table{width:100%;border-collapse:collapse;margin-top:14px;font-size:12px}
th,td{border:1px solid #d7dce5;padding:8px;text-align:center;vertical-align:middle}
th{background:#0b84f3!important;color:white!important}
tr:nth-child(even) td{background:#fafafa}
</style>
</head>
<body>${buildPrintableBudgetReport()}</body>
</html>`;

    let iframe = document.getElementById("pdfPrintFrame");
    if(iframe) iframe.remove();

    iframe = document.createElement("iframe");
    iframe.id = "pdfPrintFrame";
    iframe.style.position = "fixed";
    iframe.style.left = "0";
    iframe.style.bottom = "0";
    iframe.style.width = "1px";
    iframe.style.height = "1px";
    iframe.style.opacity = "0";
    iframe.style.border = "0";
    iframe.style.pointerEvents = "none";
    document.body.appendChild(iframe);

    const doc = iframe.contentWindow.document;
    doc.open();
    doc.write(reportHtml);
    doc.close();

    setTimeout(() => {
      try{
        iframe.contentWindow.focus();
        iframe.contentWindow.print();
      }catch(err){
        console.error("iframe print failed", err);
        alert("הדפסה נכשלה. נסה לפתוח את הדוח שוב או להשתמש בייצוא HTML.");
      }
    }, 800);
  }catch(err){
    console.error("printPdfPreview failed", err);
    alert("הדפסה נכשלה. נסה שוב.");
  }
};


window.exportPDF = function(){
  try{
    const old = document.getElementById("pdfPreviewOverlay");
    if(old) old.remove();

    const overlay = document.createElement("div");
    overlay.id = "pdfPreviewOverlay";
    overlay.innerHTML = `
      <div class="pdfPreviewToolbar noPrint">
        <button type="button" onclick="closePdfPreview()">⬅ חזרה לאפליקציה</button>
        <button type="button" class="export" onclick="printPdfPreview()">🖨️ הדפסה / שמירה כ-PDF</button>
      </div>
      <div class="pdfPreviewContent">
        ${buildPrintableBudgetReport()}
      </div>
    `;
    document.body.appendChild(overlay);
    document.body.classList.add("pdfPreviewOpen");
    setTimeout(() => window.scrollTo(0, 0), 50);
  }catch(err){
    console.error("exportPDF failed", err);
    alert("פתיחת תצוגת PDF נכשלה. אפשר להשתמש בייצוא HTML כחלופה.");
  }
};





applySavedTheme();
["amount","currency","paymentMethod"].forEach(id => {
  const el = document.getElementById(id);
  if(el){
    el.addEventListener("input", renderExpenseFeePreview);
    el.addEventListener("change", renderExpenseFeePreview);
  }
});
setTimeout(renderExpenseFeePreview, 80);
setTimeout(initAppTabs, 50);

async function forceFirebaseServerRefresh(reason = "כניסה לאפליקציה"){
  try{
    setSyncStatus("pending", "מרענן נתונים מהענן...", "מבצע קריאה ישירה מ-Firebase ולא מסתמך רק על זיכרון מקומי.");

    const [ratesSnap, tripsSnap, expensesSnap] = await Promise.all([
      getDocFromServer(doc(db, "settings", "rates")),
      getDocsFromServer(collection(db, "trips")),
      getDocsFromServer(collection(db, "expenses"))
    ]);

    if(ratesSnap.exists()){
      rates = {...rates, ...ratesSnap.data()};
    }

    trips = [];
    tripsSnap.forEach(d => trips.push({id:d.id, ...d.data()}));
    if(!trips.find(t => t.id === defaultTrip.id)){
      trips.push(defaultTrip);
    }

    expenses = [];
    expensesSnap.forEach(d => expenses.push({id:d.id, ...d.data()}));

    renderAll();
    setSyncStatus("online", "מחובר ומסונכרן", "הנתונים רועננו ישירות מהענן: " + reason);
  }catch(err){
    console.error("forceFirebaseServerRefresh failed", err);
    setSyncStatus("pending", "הרענון הישיר נכשל", "ממשיך לעבוד עם הסנכרון הרגיל. בדוק חיבור אינטרנט ונסה שוב.");
  }
}

window.forceFirebaseServerRefresh = forceFirebaseServerRefresh;

async function startBudgetAppData(){
  await ensureDefaultSettings();
  await forceFirebaseServerRefresh('כניסה לאפליקציה');

onSnapshot(doc(db, "settings", "rates"), async (snap) => {
  if(snap.exists()){
    rates = {...rates, ...snap.data()};
  }
  renderAll();
  await freezeLegacyExpensesOnce();
});

onSnapshot(collection(db, "trips"), (snap) => {
  trips = [];
  snap.forEach(d => trips.push({id:d.id, ...d.data()}));
  if(!trips.find(t => t.id === defaultTrip.id)){
    trips.push(defaultTrip);
  }
  renderTripSelector();
  renderAll();
});

onSnapshot(collection(db, "expenses"), (snap) => {
  expenses = [];
  snap.forEach(d => expenses.push({id:d.id, ...d.data()}));
  renderAll();
});

}
</script>

<style>


.budgetAppVersionBadge{
  display:inline-block;
  margin-top:12px;
  padding:7px 12px;
  border-radius:999px;
  background:rgba(255,255,255,.16);
  border:1px solid rgba(255,255,255,.35);
  color:#fff;
  font-size:12px;
  font-weight:900;
  direction:ltr;
  unicode-bidi:isolate;
}
.budgetSourceRow{display:grid;grid-template-columns:minmax(0,1fr) minmax(150px,.75fr) auto;gap:8px;align-items:end;margin-top:8px}
.budgetSourceRow input,.budgetSourceRow select,.budgetSourceRow button{margin-top:0}
@media(max-width:600px){.budgetSourceRow{grid-template-columns:1fr 1fr}.budgetSourceRow .budgetSourceRemove{grid-column:1/-1;width:100%}}

*{box-sizing:border-box}
html{direction:rtl}
body{
  font-family:Arial,"Noto Sans Hebrew",sans-serif;
  background:#f4f7fb;
  color:#111827;
  padding:15px;
  margin:0;
}
.container{
  max-width:980px;
  margin:auto;
  background:#fff;
  padding:18px;
  border-radius:18px;
  box-shadow:0 2px 14px rgba(15,23,42,.10);
}
.card{
  background:#eef6ff;
  border:1px solid #dbeafe;
  border-radius:16px;
  padding:14px;
  margin-top:14px;
  line-height:1.7;
}
h1,h2,h3{margin-top:0}
input,select,button{
  width:100%;
  box-sizing:border-box;
  padding:13px;
  margin-top:10px;
  border-radius:10px;
  border:1px solid #cbd5e1;
  font-size:16px;
}
button{
  background:#007aff;
  color:white;
  border:none;
  font-weight:900;
  cursor:pointer;
}
button.export{background:#2e7d32}
button.orange{background:#ef6c00}
button.danger{background:#c62828}
button.secondaryBtn,.secondaryBtn{background:#475569}
.smallBtn{padding:6px;margin:0;font-size:12px}
.small{font-size:13px;color:#555}
.expenseSubLine{display:block;font-size:11px;line-height:1.25;color:#475569;font-weight:800;white-space:normal}
.fxFeePreview{
  margin-top:10px;
  padding:10px 12px;
  border-radius:14px;
  background:#f8fafc;
  border:1px solid #dbeafe;
  color:#334155;
  font-size:14px;
  line-height:1.45;
  font-weight:800;
}
.fxFeePreview.feeActive{background:#fff7ed;border-color:#fed7aa;color:#7c2d12}

.rowActions{display:flex;gap:6px;justify-content:center;align-items:center;flex-wrap:wrap}
.rowActions .smallBtn{width:auto;min-width:54px}
label{display:block;margin-top:10px;color:#1f2937}
#expenseCancelEditButton{margin-top:8px}
.red{color:#b71c1c;font-weight:900}
.green{color:#1b5e20;font-weight:900}
.red-cell{background:#ffcdd2;color:#b71c1c;font-weight:900}
.noPrint{}

.authOverlay{
  position:fixed;
  inset:0;
  z-index:999999;
  background:linear-gradient(135deg,#0f172a,#1e293b,#111827);
  display:flex;
  align-items:center;
  justify-content:center;
  padding:18px;
  direction:rtl;
}
.authCard{
  width:100%;
  max-width:460px;
  background:#fff;
  border-radius:26px;
  padding:24px;
  box-shadow:0 22px 60px rgba(0,0,0,.32);
}
.authCard h1{margin:0 0 8px;font-size:30px;text-align:center}
.authCard p{color:#475569;text-align:center;margin:0 0 18px;font-weight:700}
.authCard label{font-weight:900;margin-top:10px;display:block}
.authCard input{direction:ltr;text-align:left}
.authCard button{background:linear-gradient(135deg,#2563eb,#06b6d4)}
.authCard .authSecondary{background:#475569}
.authMessage{margin-top:12px;text-align:center;font-weight:900;color:#991b1b;min-height:24px}
.authHint{
  margin-top:14px;
  background:#f8fafc;
  border:1px solid #e2e8f0;
  border-radius:14px;
  padding:12px;
  font-size:14px;
  color:#475569;
  line-height:1.45;
}
body.authLocked .container,
body.authLocked #floatingBottomButton,
body.authLocked #force-cloud-refresh-btn{display:none!important}

.authTopBar,.syncStatusBar{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:10px;
  border-radius:16px;
  padding:10px 12px;
  margin:10px 0 14px;
  font-size:14px;
  font-weight:900;
}
.authTopBar{background:#ecfeff;border:1px solid #a5f3fc;color:#155e75}
.authTopBar button{width:auto;padding:8px 12px;border-radius:12px;background:#0f766e}
.syncStatusBar{background:#f8fafc;border:1px solid #cbd5e1;color:#334155}
.syncStatusBar .dot{width:11px;height:11px;border-radius:999px;display:inline-block;margin-left:7px;background:#64748b}
.syncStatusBar.online .dot{background:#16a34a}
.syncStatusBar.offline .dot{background:#f97316}
.syncStatusBar.pending .dot{background:#dc2626}
.syncStatusBar small{display:block;font-size:12px;color:#64748b;font-weight:700;margin-top:2px}

.proHeader{
  padding:18px 16px;
  border-radius:28px;
  background:linear-gradient(135deg,#0f172a,#1e3a8a 58%,#0891b2);
  color:#fff;
  margin:12px 0 14px;
  box-shadow:0 16px 40px rgba(15,23,42,.28);
}
.proHeader h1{font-size:28px;margin:0;color:#fff}
.proHeaderSub{margin-top:8px;font-weight:800;opacity:.9;line-height:1.35}
.appVersionBadge{position:sticky;top:0;z-index:1200;display:inline-block;margin-top:10px;padding:6px 10px;border-radius:999px;background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.28);font-size:12px;font-weight:900}
.featureVerificationBox{margin-bottom:12px;padding:10px 12px;border-radius:12px;background:#ecfdf5;border:1px solid #86efac;color:#166534;font-size:13px;font-weight:900;line-height:1.45}

.appTabs{
  position:sticky;
  top:0;
  z-index:999;
  display:flex;
  gap:8px;
  overflow-x:auto;
  padding:12px 6px;
  margin:10px 0 16px;
  background:rgba(248,250,252,.96);
  backdrop-filter:blur(10px);
  border:1px solid #dbeafe;
  border-radius:18px;
  -webkit-overflow-scrolling:touch;
}
.appTabs button{
  width:auto;
  min-width:max-content;
  flex:0 0 auto;
  border-radius:999px;
  padding:12px 18px;
  font-size:16px;
  background:#e2e8f0;
  color:#0f172a;
  margin:0;
  box-shadow:none;
}
.appTabs button.active{
  background:linear-gradient(135deg,#2563eb,#06b6d4);
  color:#fff;
}

.tabPanel{display:none!important}
.tabPanel.active{display:block!important}
body.tab-main #tabMain,
body.tab-summary #tabSummary,
body.tab-charts #tabCharts,
body.tab-compare #tabCompare,
body.tab-settings #tabSettings{display:block!important}
body.tab-main #tabSummary,body.tab-main #tabCharts,body.tab-main #tabCompare,body.tab-main #tabSettings,
body.tab-summary #tabMain,body.tab-summary #tabCharts,body.tab-summary #tabCompare,body.tab-summary #tabSettings,
body.tab-charts #tabMain,body.tab-charts #tabSummary,body.tab-charts #tabCompare,body.tab-charts #tabSettings,
body.tab-compare #tabMain,body.tab-compare #tabSummary,body.tab-compare #tabCharts,body.tab-compare #tabSettings,
body.tab-settings #tabMain,body.tab-settings #tabSummary,body.tab-settings #tabCharts,body.tab-settings #tabCompare{display:none!important}

.homeKpiGrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:12px 0}
.homeKpi{
  background:#fff;
  border:1px solid #e5e7eb;
  border-radius:20px;
  padding:14px;
  box-shadow:0 8px 22px rgba(15,23,42,.06);
}
.homeKpiTitle{font-size:13px;color:#64748b;font-weight:900;margin-bottom:8px}
.homeKpiValue{font-size:22px;font-weight:1000;color:#0f172a}
.homeKpiSub{font-size:12px;color:#64748b;margin-top:6px;line-height:1.35;font-weight:700}
.homeQuickActions{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px}
.homeQuickActions button{border-radius:18px;padding:14px 12px;font-weight:1000;font-size:15px;background:#e0f2fe;color:#075985}
.homeQuickActions button.primary{background:linear-gradient(135deg,#2563eb,#06b6d4);color:#fff}
.homeMiniNote{
  margin-top:12px;
  padding:12px;
  border-radius:16px;
  background:#f8fafc;
  border:1px solid #e2e8f0;
  color:#475569;
  font-size:13px;
  font-weight:800;
  line-height:1.45;
}

table{width:100%;border-collapse:collapse;margin-top:12px;background:white;font-size:13px}
th,td{border:1px solid #ddd;padding:8px;text-align:center}
th{background:#007aff;color:white}
.tableWrap{overflow-x:auto}


.expensesLedgerWrap{
  width:100%;
  max-height:520px;
  overflow:auto;
  -webkit-overflow-scrolling:touch;
  margin-top:14px;
  background:#fff;
  border:1px solid #d7dce5;
}
#expensesTable.expensesLedgerTable{
  width:max-content;
  min-width:100%;
  max-width:none;
  table-layout:auto;
  border-collapse:collapse;
  direction:rtl;
  background:#fff;
  color:#111827;
  font-size:clamp(9px,2.45vw,13px);
}
#expensesTable.expensesLedgerTable :is(thead,tbody,tr,th,td){display:revert}
#expensesTable.expensesLedgerTable :is(th,td){
  border:1px solid #d7dce5;
  padding:6px 4px;
  text-align:center;
  vertical-align:middle;
  line-height:1.18;
  white-space:nowrap;
  word-break:normal;
  overflow-wrap:normal;
}
#expensesTable.expensesLedgerTable thead th{
  background:#0b84f3;
  color:#fff;
  font-weight:900;
  position:sticky;
  top:0;
  z-index:6;
}
#expensesTable.expensesLedgerTable tbody tr:nth-child(odd) td{background:#fff}
#expensesTable.expensesLedgerTable tbody tr:nth-child(even) td{background:#fafafa}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(1){min-width:54px}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(2){min-width:64px;font-weight:800}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(3){min-width:120px}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(4){min-width:58px}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(5){min-width:38px}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(6){min-width:70px;font-weight:900}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(7){min-width:48px}
#expensesTable.expensesLedgerTable :is(th,td):nth-child(8){min-width:42px}
#expensesTable.expensesLedgerTable td::before{content:none!important;display:none!important}
#expensesTable.expensesLedgerTable .danger.smallBtn{
  background:#d32027;
  color:#fff;
  border:none;
  border-radius:10px;
  width:100%;
  max-width:42px;
  height:28px;
  padding:0;
  font-size:12px;
  line-height:28px;
  font-weight:900;
}

.dashboardGrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:14px}
.dashCard{
  background:#fff;
  border:1px solid #dbeafe;
  border-radius:16px;
  padding:14px;
  box-shadow:0 2px 8px rgba(0,0,0,.06);
}
.dashTitle{font-size:13px;color:#475569;font-weight:bold}
.dashValue{font-size:22px;font-weight:900;margin-top:4px}
.statusGood{color:#1b5e20}
.statusWarn{color:#ef6c00}
.statusBad{color:#b71c1c}
.progressWrap{width:100%;height:22px;background:#e5e7eb;border-radius:999px;overflow:hidden;margin-top:10px;border:1px solid #cbd5e1}
.progressBar{height:100%;width:0%;background:#16a34a;transition:width .25s ease,background .25s ease}
.dashboardNote{margin-top:8px;font-size:14px;color:#475569}
.chartGrid{display:grid;grid-template-columns:1fr;gap:14px;margin-top:12px}
.chartBox{background:#fff;border:1px solid #e5e7eb;border-radius:16px;padding:14px}
.chartCanvas{width:100%;max-width:100%;height:220px}
.legendItem{display:flex;align-items:center;gap:8px;margin:5px 0;font-size:14px}
.legendColor{width:14px;height:14px;border-radius:4px;display:inline-block;flex:0 0 auto}

.filterPanel,.compareControls{
  background:#f8fafc;
  border:1px solid #dbeafe;
  border-radius:14px;
  padding:12px;
  margin-top:12px;
}
.categoryTotalsGrid{display:grid;grid-template-columns:1fr;gap:8px;margin-top:10px}
.categoryTotalItem{background:#fff;border:1px solid #e5e7eb;border-radius:12px;padding:10px;font-weight:800}
.dateChips{display:flex;flex-wrap:wrap;gap:7px;margin-top:10px}
.dateChip{
  width:auto;
  padding:8px 10px;
  border-radius:999px;
  background:#e0f2fe;
  color:#075985;
  border:1px solid #7dd3fc;
  font-size:13px;
  font-weight:800;
}
.dateChip.active{background:#2563eb;color:white;border-color:#2563eb}
.tripCheckGrid{display:grid;grid-template-columns:1fr;gap:8px;margin-top:8px}
.tripCheckItem{
  background:#fff;
  border:1px solid #e5e7eb;
  border-radius:12px;
  padding:10px;
  display:flex;
  align-items:center;
  gap:8px;
  font-weight:800;
}
.tripCheckItem input{width:auto;margin:0}
.compareResultCard{margin-top:12px;background:#fff;border:1px solid #e5e7eb;border-radius:14px;padding:12px}
.collapsiblePanel{display:none;margin-top:12px}
.collapsiblePanel.open{display:block}
.tripActions{display:flex;gap:8px;flex-wrap:wrap}
.tripActions button{flex:1 1 160px}

.tripBudgetSummaryBox{
  margin-top:14px;
  padding:16px;
  border-radius:18px;
  background:linear-gradient(135deg,#eff6ff 0%,#f8fafc 100%);
  border:1px solid #bfdbfe;
}
.tripBudgetSummaryGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
.tripBudgetCard{background:white;border-radius:16px;padding:14px;border:1px solid #dbeafe}
.tripBudgetCard h4{margin:0 0 10px;font-size:16px}
.tripBudgetMain{font-size:22px;font-weight:900;margin-bottom:6px}
.tripBudgetSub{font-size:13px;color:#475569;line-height:1.45}
.tripBudgetGood{color:#15803d}
.tripBudgetWarn{color:#d97706}
.tripBudgetBad{color:#dc2626}

.ratesHeadline{
  background:#fff8e1;
  border:2px solid #ffca28;
  border-radius:12px;
  padding:12px;
  margin-top:10px;
  font-size:17px;
}
.rateLine{
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:10px;
  direction:rtl;
  border-bottom:1px solid rgba(0,0,0,.08);
  padding:6px 0;
}
.rateLine:last-child{border-bottom:0}
.rateLine span:first-child{font-weight:700}
.rateLine b{white-space:nowrap}
.rateInputWrap{margin-top:12px}
.rateInputWrap label{display:block;font-weight:900;margin:10px 0 4px}
.budgetSourceRow{display:grid;grid-template-columns:minmax(0,1fr) minmax(150px,1fr) auto;gap:8px;align-items:end;margin-top:8px}
.budgetSourceRow input,.budgetSourceRow select,.budgetSourceRow button{margin-top:0}
.budgetSourceRow .budgetSourceRemove{width:auto;min-width:62px;height:48px}
.budgetSourceRow .budgetSourceRemove:disabled{opacity:.45;cursor:not-allowed}
@media(max-width:520px){.budgetSourceRow{grid-template-columns:1fr 1fr}.budgetSourceRow .budgetSourceRemove{grid-column:1/-1;width:100%}}

.appCreatorFooter{
  margin-top:40px;
  padding:18px;
  border-top:1px solid #dbeafe;
  text-align:center;
  font-size:14px;
  color:#475569;
  opacity:.95;
}
.appCreatorFooter .creatorName{font-weight:800;font-size:16px;margin-bottom:6px}

#force-cloud-refresh-btn{
  position:fixed;
  left:14px;
  bottom:calc(126px + env(safe-area-inset-bottom,0px));
  z-index:2147483647;
  min-width:118px;
  min-height:42px;
  padding:10px 14px;
  border:1px solid rgba(255,255,255,.35);
  border-radius:999px;
  background:linear-gradient(135deg,#0f766e,#2563eb);
  color:#fff;
  font-size:14px;
  font-weight:900;
  box-shadow:0 6px 18px rgba(0,0,0,.28);
}

#pdfPreviewOverlay{
  position:fixed;
  inset:0;
  z-index:2147483647;
  display:flex;
  flex-direction:column;
  background:#f8fafc;
  color:#111827;
  direction:rtl;
  overflow:hidden;
  height:100vh;
}
body.pdfPreviewOpen{
  overflow:hidden;
  height:100vh;
}
.pdfPreviewToolbar{
  flex:0 0 auto;
  display:flex;
  gap:10px;
  padding:12px;
  background:rgba(248,250,252,.96);
  border-bottom:1px solid #d7dce5;
  backdrop-filter:blur(10px);
  z-index:10;
}
.pdfPreviewToolbar button{
  width:auto;
  flex:1;
  margin:0;
  border-radius:14px;
  padding:12px;
  font-weight:900;
}
.pdfPreviewContent{
  flex:1 1 auto;
  min-height:0;
  overflow-y:auto;
  overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  padding:18px;
}
.printReport{
  max-width:980px;
  margin:0 auto;
  background:#fff;
  border:1px solid #d7dce5;
  border-radius:16px;
  padding:18px;
}
.printReport h1,.printReport h2{text-align:center;margin:10px 0}
.printReport .meta{text-align:center;color:#475569;margin-bottom:18px}
.printReport .summary{border:1px solid #d7dce5;border-radius:14px;padding:14px;margin:14px 0;line-height:1.8}
.printReport table{width:100%;border-collapse:collapse;margin-top:14px;font-size:12px;background:#fff}
.printReport th,.printReport td{border:1px solid #d7dce5;padding:8px;text-align:center;vertical-align:middle;color:#111827}
.printReport th{background:#0b84f3!important;color:#fff!important}
.printReport tr:nth-child(even) td{background:#fafafa}
body.pdfPreviewOpen .container,
body.pdfPreviewOpen #authOverlay,
body.pdfPreviewOpen #force-cloud-refresh-btn{display:none!important}
#pdfPrintFrame{display:block!important}

body.darkMode{
  background:#0f172a;
  color:#e5e7eb;
}
body.darkMode .container,
body.darkMode .card,
body.darkMode .chartBox,
body.darkMode .dashCard,
body.darkMode .categoryTotalItem,
body.darkMode .compareResultCard,
body.darkMode .tripCheckItem{
  background:#111827;
  color:#e5e7eb;
  border-color:#374151;
}
body.darkMode input,body.darkMode select{
  background:#0f172a;
  color:#e5e7eb;
  border-color:#475569;
}
body.darkMode .appTabs{background:rgba(15,23,42,.96);border-color:#334155}
body.darkMode .appTabs button{background:#1f2937;color:#e5e7eb}
body.darkMode .appTabs button.active{background:linear-gradient(135deg,#2563eb,#06b6d4);color:#fff}
body.darkMode .homeKpi,
body.darkMode .tripBudgetCard{background:#1f2937;border-color:#374151}
body.darkMode .homeKpiValue{color:#e5e7eb}
body.darkMode .homeKpiTitle,body.darkMode .homeKpiSub,body.darkMode .dashboardNote,body.darkMode .small{color:#cbd5e1}
body.darkMode .expensesLedgerWrap,
body.darkMode #expensesTable.expensesLedgerTable{background:#fff!important;color:#111827!important}
body.darkMode #expensesTable.expensesLedgerTable th,
body.darkMode #expensesTable.expensesLedgerTable td{border-color:#d7dce5!important;color:#111827!important}
body.darkMode #expensesTable.expensesLedgerTable thead th{background:#0b84f3!important;color:#fff!important}

@media(min-width:650px){
  .categoryTotalsGrid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(min-width:700px){
  .tripCheckGrid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(min-width:760px){
  .dashboardGrid{grid-template-columns:repeat(4,minmax(0,1fr))}
  .chartGrid{grid-template-columns:1fr 1fr}
}
@media(max-width:700px){
  body{padding:10px}
  .container{padding:12px;border-radius:14px}
  .homeKpiGrid,.homeQuickActions{grid-template-columns:1fr}
  .proHeader h1{font-size:24px}
  .appTabs button{font-size:14px;padding:10px 14px}
  .chartGrid{grid-template-columns:1fr}
  .chartCanvas{width:100%;max-width:100%}
  table.mobileCards,table.mobileCards thead,table.mobileCards tbody,table.mobileCards tr,table.mobileCards th,table.mobileCards td{display:block;width:100%}
  table.mobileCards thead{display:none}
  table.mobileCards tr{background:rgba(255,255,255,.92);border:1px solid #e5e7eb;border-radius:16px;margin:10px 0;padding:10px;box-shadow:0 4px 12px rgba(15,23,42,.06)}
  table.mobileCards td{border:0!important;padding:8px 4px!important;text-align:right!important;display:flex;justify-content:space-between;gap:12px;align-items:flex-start;white-space:normal!important;word-break:break-word}
  table.mobileCards td::before{content:attr(data-label);font-weight:900;color:#64748b;min-width:100px;flex:0 0 42%}
}
@media(max-width:430px){
  .expensesLedgerWrap{max-height:500px;margin-left:-10px;margin-right:-10px}
  #expensesTable.expensesLedgerTable{font-size:9px}
  #expensesTable.expensesLedgerTable th,#expensesTable.expensesLedgerTable td{padding:5px 2px}
}
@media print{
  .noPrint,.pdfPreviewToolbar,#force-cloud-refresh-btn{display:none!important}
  body.pdfPreviewOpen{overflow:visible!important;height:auto!important;background:#fff!important}
  body.pdfPreviewOpen #pdfPreviewOverlay{position:static!important;display:block!important;height:auto!important;overflow:visible!important;background:#fff!important}
  body.pdfPreviewOpen .pdfPreviewContent{overflow:visible!important;padding:0!important}
  body.pdfPreviewOpen .printReport{border:0!important;border-radius:0!important;padding:0!important}
  .container{box-shadow:none}
}



.tabPanel,.card[id$="Anchor"]{scroll-margin-top:92px}
</style>

<script>
(function(){
  function showTabVisual(tabId, shouldScroll){
    const map = {
      tabMain: "tab-main",
      tabSummary: "tab-summary",
      tabCharts: "tab-charts",
      tabCompare: "tab-compare",
      tabSettings: "tab-settings"
    };
    const scrollMap = {
      tabMain: "tabMain",
      tabSummary: "summaryAnchor",
      tabCharts: "chartsInfoAnchor",
      tabCompare: "compareAnchor",
      tabSettings: "settingsExportAnchor"
    };
    const cls = map[tabId] || "tab-main";
    document.body.classList.remove("tab-main","tab-summary","tab-charts","tab-compare","tab-settings");
    document.body.classList.add(cls);
    document.querySelectorAll(".tabPanel").forEach(p => p.classList.remove("active"));
    const panel = document.getElementById(tabId);
    if(panel) panel.classList.add("active");
    document.querySelectorAll(".appTabs button").forEach(b => b.classList.remove("active"));
    const btn = document.querySelector(`[data-tab-btn="${tabId}"]`);
    if(btn) btn.classList.add("active");
    try{ localStorage.setItem("activeBudgetTab", tabId); }catch(err){}
    if(shouldScroll !== false){
      const target = document.getElementById(scrollMap[tabId] || tabId) || panel;
      if(target){
        setTimeout(() => {
          try{ target.scrollIntoView({behavior:"smooth", block:"start"}); }
          catch(err){ target.scrollIntoView(true); }
        }, 30);
      }
    }
  }
  if(typeof window.showAppTab !== "function"){
    window.showAppTab = showTabVisual;
  }
  window.addEventListener("DOMContentLoaded", function(){
    if(typeof window.showAppTab !== "function") window.showAppTab = showTabVisual;
    const saved = localStorage.getItem("activeBudgetTab") || "tabMain";
    showTabVisual(saved, false);
  });
})();
</script>

</head>
<body class="authLocked tab-main">
<div id="authOverlay" class="authOverlay">
  <div class="authCard">
    <h1>🔐 כניסה מאובטחת</h1>
    <p>אפליקציית ניהול תקציב החופשה</p>
    <label for="authEmail">אימייל</label>
    <input id="authEmail" type="email" autocomplete="username" placeholder="example@gmail.com">
    <label for="authPassword">סיסמה</label>
    <input id="authPassword" type="password" autocomplete="current-password" placeholder="הכנס סיסמה">
    <button onclick="loginBudgetApp()">כניסה לאפליקציה</button>
    <button class="authSecondary" onclick="createBudgetUser()">יצירת משתמש מורשה ראשון</button>
    <div id="authMessage" class="authMessage"></div>
    <div class="authHint">ניתן לשמור את הסיסמה באייפון ולהשתמש ב־Face ID למילוי מהיר.</div>
  </div>
</div>
<div class="container">
<div id="authTopBar" class="authTopBar" style="display:none;">
  <span id="authUserLabel">מחובר</span>
  <button onclick="logoutBudgetApp()">התנתקות</button>
</div>
<div id="syncStatusBar" class="syncStatusBar offline">
  <div>
    <span class="dot"></span><span id="syncStatusText">בודק חיבור וסנכרון...</span>
    <small id="syncStatusSub">שינויים שתזין אופליין יישמרו מקומית ויסונכרנו כשיחזור אינטרנט.</small>
  </div>
</div>
<div class="proHeader">
  <div class="proHeaderTop">
    <h1>ניהול תקציב חופשה</h1>
  </div>
  <div class="proHeaderSub">תקציב חי, הוצאות, סיכומים והשוואת טיולים</div>
  <div id="budgetAppVersionBadge" class="budgetAppVersionBadge">גרסת מטבע חוץ ותקציבי ילדים · 2026.07.15-FX-KIDS-v4</div>
  <div class="appVersionBadge">גרסת מטבע חוץ ותקציבים פרטיים · 2026.07.15-v3</div>
</div>
<div class="appTabs noPrint">
  <button data-tab-btn="tabMain" onclick="showAppTab('tabMain')">🏠 ראשי</button>
  <button data-tab-btn="tabSummary" onclick="showAppTab('tabSummary')">💰 סיכומים</button>
  <button data-tab-btn="tabCharts" onclick="showAppTab('tabCharts')">📊 מידע גרפי</button>
  <button data-tab-btn="tabCompare" onclick="showAppTab('tabCompare')">⚖️ השוואה</button>
  <button data-tab-btn="tabSettings" onclick="showAppTab('tabSettings')">⚙️ הגדרות וייצוא</button>
</div>



<div id="tabMain" class="tabPanel active">
<div class="card section-main-home noPrint">
  <h2>🧳 בחירת טיול פעיל</h2>
  <label><b>טיול פעיל:</b></label>
  <select id="homeTripSelector" onchange="switchTripFromHome()"></select>
</div>

<div class="card section-main-home">
  <h2>🏠 מסך ראשי</h2>
  <div class="homeKpiGrid">
    <div class="homeKpi">
      <div class="homeKpiTitle">טיול פעיל</div>
      <div class="homeKpiValue" id="homeTripName">—</div>
      <div class="homeKpiSub">לפי בחירת הטיול הפעיל</div>
    </div>
    <div class="homeKpi">
      <div class="homeKpiTitle">נותר בתקציב הכולל</div>
      <div class="homeKpiValue" id="homeTotalLeft">—</div>
      <div class="homeKpiSub" id="homeTotalUsed">—</div>
    </div>
    <div class="homeKpi">
      <div class="homeKpiTitle">נותר בקניות</div>
      <div class="homeKpiValue" id="homeShoppingLeft">—</div>
      <div class="homeKpiSub" id="homeShoppingUsed">—</div>
    </div>
    <div class="homeKpi">
      <div class="homeKpiTitle">תקציב אוכל יומי</div>
      <div class="homeKpiValue" id="homeFoodBudget">—</div>
      <div class="homeKpiSub" id="homeFoodSub">יעד יומי פעיל</div>
    </div>
  </div>
  <div class="homeQuickActions noPrint">
    <button class="primary" onclick="document.getElementById('quickExpenseCard')?.scrollIntoView({behavior:'smooth'});">➕ הוספת הוצאה</button>
    <button onclick="showAppTab('tabSummary')">💰 סיכום מלא</button>
    <button onclick="showAppTab('tabCharts')">📊 גרפים</button>
    <button onclick="showAppTab('tabCompare')">⚖️ השוואת טיולים</button>
  </div>
  <div class="homeMiniNote">עדכון מהיר של הוצאות ומעקב תקציב בזמן אמת.</div>
</div>

<div id="quickExpenseCard" class="card noPrint section-main">
<h2 id="expenseFormTitle">➕ הוספת הוצאה</h2>
<label for="category"><b>קטגוריה:</b></label>
<select id="category" aria-label="קטגוריה">
<option value="">בחר קטגוריה</option>
<option>כרטיסי סים</option>
<option>אוכל</option>
<option>קניות עידו</option>
<option>קניות מיכאל</option>
<option>ביגוד והנעלה</option>
<option>תחבורה ציבורית</option>
<option>אטרקציות</option>
<option>תשלומים במזומן</option>
<option>מלונות</option>
<option>ביטוח נסיעות</option>
<option>טיסות</option>
<option>השכרת רכב</option>
<option>דלק</option>
<option>טיפים</option>
<option>כביסות</option>
<option>קרוז</option>
<option>שונות</option>
</select>
<label for="note"><b>פירוט:</b></label>
<input id="note" placeholder="שם מקום / פירוט" autocomplete="off" aria-label="פירוט ההוצאה">
<label for="amount"><b>סכום:</b></label>
<input id="amount" type="number" inputmode="decimal" min="0" step="0.01" placeholder="סכום" aria-label="סכום ההוצאה">
<label for="currency"><b>מטבע:</b></label>
<select id="currency" aria-label="מטבע">
<option value="ILS">₪ שקל</option>
<option value="USD">$ דולר אמריקאי</option>
<option value="JPY">¥ ין</option>
<option value="EUR">€ יורו</option>
<option value="GBP">£ לירה סטרלינג</option>
<option value="CAD">C$ דולר קנדי</option>
</select>
<label for="budgetOwner"><b>מאיזה תקציב ההוצאה?</b></label>
<select id="budgetOwner" aria-label="שיוך תקציב">
<option value="home" selected>תקציב הבית</option>
<option value="ido">תקציב עידו פרטי</option>
<option value="michael">תקציב מיכאל פרטי</option>
</select>
<label for="paymentMethod"><b>אמצעי תשלום:</b></label>
<select id="paymentMethod" aria-label="אמצעי תשלום">
<option value="credit" selected>אשראי</option>
<option value="cash">מזומן</option>
</select>
<div id="fxFeePreview" class="fxFeePreview">הזן סכום כדי לראות את חישוב השקלים והאם יש עמלת אשראי מט״ח.</div>
<label for="expenseDate"><b>תאריך ההוצאה:</b></label>
<input id="expenseDate" type="date" aria-label="תאריך ההוצאה">
<button id="expenseSubmitButton" onclick="addExpense()">הוסף הוצאה</button>
<button id="expenseCancelEditButton" class="secondaryBtn" style="display:none" onclick="cancelExpenseEdit()">ביטול עריכה</button>
</div>



<div class="card section-main">
<h2 id="mainExpensesAnchor">פירוט כל ההוצאות בטיול הפעיל</h2>

<button id="refreshMainExpensesButton" class="noPrint" onclick="renderExpenses()">רענון טבלת הוצאות</button>
<div class="expensesLedgerWrap">
<table id="expensesTable" class="expensesLedgerTable">
<thead><tr><th>תאריך</th><th>תקציב</th><th>קטגוריה</th><th>פירוט</th><th>סכום</th><th>מטבע</th><th>סה״כ ₪</th><th>שער</th><th>פעולות</th></tr></thead>
<tbody id="expensesBody"></tbody>
</table>
</div>
</div>
</div>

<div id="tabSummary" class="tabPanel">
<div id="summaryAnchor" class="card section-summary">
<h2>💰 סיכום סופי ותקציבים</h2>
<div class="noPrint" style="margin-bottom:12px;">
<label><b>בחר מטבע להצגת הסיכום:</b></label>
<select id="summaryCurrency" onchange="setSummaryCurrencyFromUI()">
<option value="ILS">₪ שקל ישראלי</option>
<option value="USD">$ דולר אמריקאי</option>
<option value="JPY">¥ ין יפני</option>
<option value="EUR">€ יורו</option>
<option value="GBP">£ לירה סטרלינג</option>
<option value="CAD">C$ דולר קנדי</option>
</select>
</div>
<div class="small">תצוגת הסיכום לפי המטבע שנבחר.</div>
<div id="summaryFinal"></div>
<div class="summaryUnifiedBox"><div id="tripBudgetSummaryBox" class="tripBudgetSummaryBox"></div></div>
</div>

<div class="card section-summary">
<h2>סיכום יומי</h2>
<div class="tableWrap">
<table id="dailyTable" class="mobileCards">
<thead><tr><th>תאריך</th><th>סה״כ יומי</th></tr></thead>
<tbody id="dailyBody"></tbody>
</table>
</div>
</div>




<div class="card noPrint section-summary">
<h2>🔎 סינון וסיכום לפי קטגוריה</h2>
<div class="filterPanel">
<label for="filterType"><b>סוג סינון:</b></label>
<select id="filterType" onchange="setFilterTypeFromUI()">
<option value="category">לפי קטגוריה</option>
<option value="date">לפי תאריך</option>
</select>

<div id="categoryFilterBox">
<label for="categoryFilter"><b>בחר קטגוריה להצגה:</b></label>
<select id="categoryFilter" onchange="setCategoryFilterFromUI()">
<option value="ALL">כל הקטגוריות</option>
</select>
</div>

<div id="dateFilterBox" style="display:none;">
<label for="dateFilter"><b>בחר תאריך פעיל:</b></label>
<select id="dateFilter" onchange="setDateFilterFromUI()">
<option value="ALL">כל התאריכים</option>
</select>
<div id="activeDatesChips" class="dateChips"></div>
</div>

<button onclick="clearCategoryFilter()">נקה סינון</button>
<div id="selectedCategorySummary" class="dashboardNote"></div>
</div>
<h3>סה״כ לפי קטגוריות</h3>

<div id="categoryTotalsGrid" class="categoryTotalsGrid"></div>
</div>

</div>

<div id="tabCharts" class="tabPanel">
<div class="card section-charts">
<h2>📊 דשבורד תקציב מקצועי</h2>

<div class="dashboardGrid">
  <div class="dashCard">
    <div class="dashTitle">סה״כ הוצאות בכל התקציבים</div>
    <div class="dashValue" id="dashTotal">₪0</div>
  </div>
  <div class="dashCard">
    <div class="dashTitle">יתרת תקציב הבית</div>
    <div class="dashValue" id="dashRemaining">₪0</div>
  </div>
  <div class="dashCard">
    <div class="dashTitle">ניצול תקציב</div>
    <div class="dashValue" id="dashPercent">0%</div>
  </div>
  <div class="dashCard">
    <div class="dashTitle">ממוצע יומי</div>
    <div class="dashValue" id="dashAvgDaily">₪0</div>
  </div>
</div>

<div class="progressWrap">
  <div class="progressBar" id="budgetProgressBar"></div>
</div>
<div class="dashboardNote" id="budgetStatusText">אין עדיין נתונים.</div>

<div class="dashboardGrid">
  <div class="dashCard">
    <div class="dashTitle">הוצאות היום</div>
    <div class="dashValue" id="dashToday">₪0</div>
  </div>
  <div class="dashCard">
    <div class="dashTitle">אוכל היום מול יעד יומי</div>
    <div class="dashValue" id="dashFoodToday">₪0</div>
  </div>
  <div class="dashCard">
    <div class="dashTitle">ביגוד, הנעלה, ואלקטרוניקה</div>
    <div class="dashValue" id="dashClothing">₪0</div>
  </div>
  <div class="dashCard">
    <div class="dashTitle">מספר הוצאות</div>
    <div class="dashValue" id="dashCount">0</div>
  </div>
</div>




</div>

<div id="chartsInfoAnchor" class="card section-charts">
<h2>📊 מידע גרפי</h2>
<div class="chartGrid section-charts">
  <div class="chartBox">
    <h3>🍰 פריסת הוצאות לפי קטגוריה</h3>
    <canvas id="categoryPie" class="chartCanvas" width="420" height="240"></canvas>
    <div id="categoryLegend"></div>
  </div>
  <div class="chartBox">
    <h3>📈 הוצאות לפי יום</h3>
    <canvas id="dailyBar" class="chartCanvas" width="420" height="240"></canvas>
  </div>
</div>
</div>
</div>

<div id="tabCompare" class="tabPanel">
<div id="compareAnchor" class="card section-compare">
<h2>⚖️ השוואה בין טיולים</h2>
<div class="compareControls">
<div class="small">בחר טיולים ומדד להשוואה.</div>

<button class="secondaryBtn" onclick="toggleCompareTripsPanel()">🧳 בחירת טיולים להשוואה</button>
<div id="compareTripsPanel" class="collapsiblePanel">
<label><b>סמן טיולים להשוואה:</b></label>
<div id="compareTripsBox" class="tripCheckGrid"></div>
</div>

<label for="compareMetric"><b>בחר מדד להשוואה:</b></label>
<select id="compareMetric" onchange="setCompareMetricFromUI()">
<option value="TOTAL">סה״כ הוצאות</option>
<option value="DATE">תאריך מסוים</option>
<option value="MOST_EXPENSIVE_DAY">יום הכי יקר</option>
<option value="CHEAPEST_DAY">יום הכי זול</option>
<option value="CAT::כרטיסי סים">כרטיסי סים</option>
<option value="CAT::אוכל">אוכל</option>
<option value="CAT::קניות עידו">קניות עידו</option>
<option value="CAT::קניות מיכאל">קניות מיכאל</option>
<option value="CAT::ביגוד והנעלה">ביגוד והנעלה</option>
<option value="CAT::תחבורה ציבורית">תחבורה ציבורית</option>
<option value="CAT::אטרקציות">אטרקציות</option>
<option value="CAT::תשלומים במזומן">תשלומים במזומן</option>
<option value="CAT::מלונות">מלונות</option>
<option value="CAT::ביטוח נסיעות">ביטוח נסיעות</option>
<option value="CAT::טיסות">טיסות</option>
<option value="CAT::השכרת רכב">השכרת רכב</option>
<option value="CAT::דלק">דלק</option>
<option value="CAT::טיפים">טיפים</option>
<option value="CAT::כביסות">כביסות</option>
<option value="CAT::קרוז">קרוז</option>
<option value="CAT::שונות">שונות</option>
</select>

<div id="compareDateBox" style="display:none;">
<label for="compareDate"><b>בחר תאריך פעיל:</b></label>
<select id="compareDate" onchange="setCompareDateFromUI()"></select>
</div>

<div id="compareStatus" class="dashboardNote"></div>
</div>

<div class="compareResultCard">
<div class="tableWrap">
<table class="compareMiniTable mobileCards">
<thead id="tripComparisonHead"></thead>
<tbody id="tripComparisonBody"></tbody>
</table>
</div>
</div>
</div>

</div>

<div id="tabSettings" class="tabPanel">
<div id="settingsExportAnchor" class="card section-settings">
<h2>⚙️ הגדרות וייצוא</h2>
<h3>🧳 ניהול טיולים</h3>
<div class="small">הטיול הראשון מוגדר כ־<b>יפן 2026</b>. ניתן ליצור טיולים נוספים ולבחור ביניהם.</div>


<div id="activeTripLabel" class="dashboardNote">טיול פעיל: <b>יפן 2026</b></div>

<label for="tripSelector"><b>בחר טיול פעיל:</b></label>
<select id="tripSelector" onchange="switchTrip()"></select>

<div class="tripActions noPrint">
<button onclick="createNewTrip()">➕ יצירת טיול חדש</button>
<button class="secondaryBtn" onclick="toggleTripSettings()">⚙️ הגדרות הטיול הפעיל</button>
</div>

<div id="tripSettingsPanel" class="filterPanel collapsiblePanel">
<div class="featureVerificationBox"><b>גרסה פעילה:</b> מטבע חוץ + תקציב עידו + תקציב מיכאל + שיוך הוצאה לתקציב.</div>
<label for="tripName"><b>שם הטיול:</b></label>
<input id="tripName" placeholder="לדוגמה: יפן 2026 / ארה״ב 2027" oninput="saveTripName()">

<label><b>מקורות תקציב הבית:</b></label>
<div class="small">אפשר לשלב שקלים ומטבעות זרים. שווי התקציב הכולל בשקלים מחושב בכל רגע לפי השערים הפעילים.</div>
<div id="budgetSourcesRows"></div>
<button type="button" class="secondaryBtn" onclick="addBudgetSourceRow()">➕ הוספת מקור תקציב במטבע נוסף</button>
<div id="budgetSourcesPreview" class="fxFeePreview"></div>

<label for="tripIdoBudgetInput"><b>תקציב עידו פרטי בשקלים:</b></label>
<input id="tripIdoBudgetInput" type="number" inputmode="decimal" min="0" step="0.01" placeholder="0">

<label for="tripMichaelBudgetInput"><b>תקציב מיכאל פרטי בשקלים:</b></label>
<input id="tripMichaelBudgetInput" type="number" inputmode="decimal" min="0" step="0.01" placeholder="0">

<label for="tripClothingInput"><b>תקציב ביגוד, הנעלה, ואלקטרוניקה בשקלים:</b></label>
<input id="tripClothingInput" type="number" inputmode="decimal" placeholder="לדוגמה: 20000">

<label for="tripFoodInput"><b>תקציב אוכל יומי בשקלים:</b></label>
<input id="tripFoodInput" type="number" inputmode="decimal" min="0" placeholder="לדוגמה: 750">

<label for="tripTotalFoodInput"><b>מסגרת אוכל כוללת בשקלים:</b></label>
<input id="tripTotalFoodInput" type="number" inputmode="decimal" min="0" placeholder="0 אם אין מסגרת כוללת">

<button class="noPrint" onclick="saveTripSettings()">💾 שמירת הגדרות טיול</button>
</div>
</div>




<div class="card section-settings">
<b>תקציב כולל:</b> <span id="topBudgetLabel">₪93,063</span><br>
<b>תקציב ביגוד, הנעלה, ואלקטרוניקה:</b> <span id="topClothingBudgetLabel">₪20,000</span><br>
<b>תקציב אוכל יומי:</b> <span id="topFoodBudgetLabel">₪750</span><br><br>
<div class="ratesHeadline">
<b>שערי המרה פעילים להוצאות חדשות:</b><br>
<div class="rateLine"><span>USD דולר אמריקאי</span><b><span id="usdRateTop">2.9070</span> ₪</b></div>
<div class="rateLine"><span>JPY ין יפני</span><b><span id="jpyRateTop">0.018548</span> ₪</b></div>
<div class="rateLine"><span>100 ין יפני</span><b><span id="jpy100RateTop">1.8548</span> ₪</b></div>
<div class="rateLine"><span>EUR יורו</span><b><span id="eurRateTop">3.4225</span> ₪</b></div>
<div class="rateLine"><span>GBP לירה סטרלינג</span><b><span id="gbpRateTop">3.9572</span> ₪</b></div>
<div class="rateLine"><span>CAD דולר קנדי</span><b><span id="cadRateTop">2.1282</span> ₪</b></div>







</div>
<span class="small">מקור: <span id="rateSource"></span> | עודכן: <span id="rateUpdated"></span></span><br>
<span class="small"><b>חשוב:</b> הוצאות שכבר הוזנו נשארות לפי שער הכניסה שלהן ולא משתנות אחרי עדכון שערים.</span>
</div>

<div class="card noPrint section-settings">
<h2>עדכון שערים</h2>
<button onclick="updateRatesLive()">עדכון שערים בזמן אמת מהאינטרנט</button>
<div id="ratesStatus" class="small"></div><div class="small">שערים שעודכנו מהאינטרנט או ידנית נשמרים ומשמשים לכל הוצאה חדשה עד העדכון הבא.</div>
<div class="rateInputWrap">
<label for="usdRateInput">דולר אמריקאי (USD) — שער בשקלים</label>
<input id="usdRateInput" type="number" step="0.0001" placeholder="לדוגמה: 2.9090">

<label for="jpyRateInput">ין יפני (JPY) — שער בשקלים ל־1 ין</label>
<input id="jpyRateInput" type="number" step="0.000001" placeholder="לדוגמה: 0.018511">

<label for="eurRateInput">יורו (EUR) — שער בשקלים</label>
<input id="eurRateInput" type="number" step="0.0001" placeholder="לדוגמה: 3.4225">

<label for="gbpRateInput">לירה סטרלינג (GBP) — שער בשקלים</label>
<input id="gbpRateInput" type="number" step="0.0001" placeholder="לדוגמה: 3.9572">

<label for="cadRateInput">דולר קנדי (CAD) — שער בשקלים</label>
<input id="cadRateInput" type="number" step="0.0001" placeholder="לדוגמה: 2.1282">
</div>
<button onclick="saveManualRates()">עדכון שערים ידני וסנכרון</button>
</div>

<div class="card noPrint section-settings">
<h2>ייצוא ואיפוס</h2>
<button class="export" onclick="exportHTML()">ייצוא HTML</button>
<button class="export" type="button" onclick="exportPDF()">תצוגת PDF / הדפסה</button>
<div class="small">נפתח בתוך האפליקציה עם כפתור חזרה ברור.</div>
<button class="orange" onclick="clearTrip()">איפוס הוצאות הטיול הפעיל</button>
</div>

<div class="appCreatorFooter section-settings">
  <div class="creatorName">פותח ועוצב על ידי: איתן פרידמן</div>
</div>
</div>
</div>
</body>
</html>