{"id":493,"date":"2026-06-04T16:23:19","date_gmt":"2026-06-04T16:23:19","guid":{"rendered":"https:\/\/nordbalance.dk\/?page_id=493"},"modified":"2026-06-04T17:51:27","modified_gmt":"2026-06-04T17:51:27","slug":"maanedsoverblik","status":"publish","type":"page","link":"https:\/\/nordbalance.dk\/?page_id=493","title":{"rendered":"M\u00e5nedsoverblik"},"content":{"rendered":"\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@supabase\/supabase-js@2\"><\/script>\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"><\/script>\n\n<div class=\"nb-month-page\">\n\n  <div class=\"nb-top\">\n    <div>\n      <h1>M\u00e5nedsoverblik<\/h1>\n      <p>M\u00e5nedsoverblik giver dig et samlet billede af din \u00f8konomi m\u00e5ned for m\u00e5ned.<\/p>\n      <div id=\"loggedUser\" class=\"logged-user\">Tjekker login&#8230;<\/div>\n    <\/div>\n    <button class=\"logout-btn\" type=\"button\" onclick=\"logoutUser()\">Log ud<\/button>\n  <\/div>\n\n  <div class=\"nb-menu\">\n    <a href=\"https:\/\/nordbalance.dk\/?page_id=63\">\ud83d\udcca Mit Budget<\/a>\n    <a href=\"https:\/\/nordbalance.dk\/?page_id=126\">\ud83d\udcb0 Opsparing<\/a>\n    <a href=\"https:\/\/nordbalance.dk\/?page_id=130\">\ud83d\udcc8 \u00d8konomi-score<\/a>\n    <a class=\"active\" href=\"https:\/\/nordbalance.dk\/?page_id=493\">\ud83d\udcc5 M\u00e5nedsoverblik<\/a>\n    <a href=\"https:\/\/nordbalance.dk\/?page_id=195\">\ud83e\udde0 Smart Budget Planner<\/a>\n    <a href=\"https:\/\/nordbalance.dk\/?page_id=14\">\ud83e\udd16 AI Hj\u00e6lp<\/a>\n    <a href=\"https:\/\/nordbalance.dk\/?page_id=76\">\u2699\ufe0f Min Profil<\/a>\n  <\/div>\n\n  <section class=\"hero\">\n    <div>\n      <span>M\u00e5nedsoverblik over din privat\u00f8konomi<\/span>\n      <h2>M\u00e5nedsoverblik: 7 m\u00e5der at f\u00f8lge din \u00f8konomi m\u00e5ned for m\u00e5ned<\/h2>\n      <p>NordBalance henter dine gemte budgetter og viser, om din \u00f8konomi bliver bedre. F\u00f8lg indkomst, udgifter, opsparing, r\u00e5dighedsbel\u00f8b og \u00f8konomi-score i et enkelt m\u00e5nedsoverblik.<\/p>\n    <\/div>\n    <img decoding=\"async\" src=\"https:\/\/nordbalance.dk\/wp-content\/uploads\/2026\/05\/ChatGPT-Image-23.-maj-2026-12.20.05.png\" alt=\"M\u00e5nedsoverblik over \u00f8konomi m\u00e5ned for m\u00e5ned\">\n  <\/section>\n\n  <div id=\"monthStatus\" class=\"status-box info\">\n    <strong>Henter data&#8230;<\/strong>\n    <span>Vi henter dine budgetter fra Supabase.<\/span>\n  <\/div>\n\n  <section class=\"progress-box\">\n    <div>\n      <span class=\"progress-label\">\ud83c\udfc6 \u00d8konomi-udvikling<\/span>\n      <h2 id=\"progressTitle\">Henter udvikling&#8230;<\/h2>\n      <p id=\"progressText\">N\u00e5r der er mindst 2 m\u00e5neder gemt, viser NordBalance om \u00f8konomien forbedres.<\/p>\n    <\/div>\n    <div id=\"progressItems\" class=\"progress-items\">\n      <div class=\"progress-item neutral\">Gem mindst 2 m\u00e5neder for at se udvikling.<\/div>\n    <\/div>\n  <\/section>\n\n  <section class=\"summary-grid\">\n    <div class=\"summary-card\">\n      <span>Seneste m\u00e5ned<\/span>\n      <strong id=\"latestMonth\">&#8211;<\/strong>\n      <p>Den nyeste m\u00e5ned vi har fundet i dit budget.<\/p>\n    <\/div>\n    <div class=\"summary-card\">\n      <span>\u00d8konomi-score<\/span>\n      <strong id=\"latestScore\">0 \/ 100<\/strong>\n      <p id=\"scoreDiff\">Udvikling vises her.<\/p>\n    <\/div>\n    <div class=\"summary-card\">\n      <span>Udgifter<\/span>\n      <strong id=\"latestExpenses\">0 kr.<\/strong>\n      <p id=\"expenseDiff\">Udvikling vises her.<\/p>\n    <\/div>\n    <div class=\"summary-card green\">\n      <span>Opsparing<\/span>\n      <strong id=\"latestSavings\">0 kr.<\/strong>\n      <p id=\"savingDiff\">Udvikling vises her.<\/p>\n    <\/div>\n    <div class=\"summary-card\">\n      <span>R\u00e5dighedsbel\u00f8b<\/span>\n      <strong id=\"latestDisposable\">0 kr.<\/strong>\n      <p id=\"disposableDiff\">Udvikling vises her.<\/p>\n    <\/div>\n  <\/section>\n\n  <section class=\"dashboard-grid\">\n    <div class=\"chart-card\">\n      <h2>M\u00e5nedsoverblik over din \u00f8konomi<\/h2>\n      <p>Grafen viser udviklingen i \u00f8konomi-score m\u00e5ned for m\u00e5ned.<\/p>\n      <canvas id=\"scoreChart\"><\/canvas>\n    <\/div>\n\n    <div class=\"chart-card\">\n      <h2>\u00d8konomi m\u00e5ned for m\u00e5ned<\/h2>\n      <p>Her kan du sammenligne indkomst, udgifter og opsparing.<\/p>\n      <canvas id=\"moneyChart\"><\/canvas>\n    <\/div>\n\n    <div class=\"chart-card full-chart\">\n      <h2>R\u00e5dighedsbel\u00f8b m\u00e5ned for m\u00e5ned<\/h2>\n      <p>Se om du f\u00e5r flere penge tilbage efter udgifter og opsparing.<\/p>\n      <canvas id=\"disposableChart\"><\/canvas>\n    <\/div>\n  <\/section>\n\n  <section class=\"analysis-grid\">\n    <div class=\"analysis-card\">\n      <h2>Udvikling i \u00f8konomi-score<\/h2>\n      <div id=\"scoreAnalysis\">Henter analyse&#8230;<\/div>\n    <\/div>\n    <div class=\"analysis-card\">\n      <h2>Opsparing m\u00e5ned for m\u00e5ned<\/h2>\n      <div id=\"savingAnalysis\">Henter analyse&#8230;<\/div>\n    <\/div>\n    <div class=\"analysis-card\">\n      <h2>Dine vigtigste \u00e6ndringer<\/h2>\n      <div id=\"changeList\">Henter \u00e6ndringer&#8230;<\/div>\n    <\/div>\n  <\/section>\n\n  <section class=\"forecast-grid\">\n    <div class=\"forecast-card\">\n      <h2>\ud83e\udd16 AI-prognose<\/h2>\n      <p id=\"forecastText\">N\u00e5r der er nok historik, beregner NordBalance en simpel prognose for de n\u00e6ste 6 m\u00e5neder.<\/p>\n    <\/div>\n    <div class=\"forecast-card\">\n      <h2>\ud83c\udfaf N\u00e6ste m\u00e5l<\/h2>\n      <p id=\"nextGoalText\">Dit n\u00e6ste \u00f8konomiske m\u00e5l vises her.<\/p>\n    <\/div>\n  <\/section>\n\n  <section class=\"table-card\">\n    <h2>M\u00e5nedsoverblik i tabel<\/h2>\n    <div class=\"table-wrap\">\n      <table>\n        <thead>\n          <tr>\n            <th>M\u00e5ned<\/th>\n            <th>Indkomst<\/th>\n            <th>Udgifter<\/th>\n            <th>Opsparing<\/th>\n            <th>R\u00e5dighedsbel\u00f8b<\/th>\n            <th>Score<\/th>\n            <th>Handling<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"monthTable\">\n          <tr><td colspan=\"7\">Henter data&#8230;<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n  <\/section>\n\n  <section class=\"ai-box\">\n    <h2>\ud83e\udd16 AI-anbefaling til dit m\u00e5nedsoverblik<\/h2>\n    <p id=\"aiAdvice\">N\u00e5r dine budgetter er hentet, f\u00e5r du en samlet vurdering her.<\/p>\n  <\/section>\n\n  <section class=\"seo-box\">\n    <h2>Hvordan bruger du et m\u00e5nedsoverblik?<\/h2>\n    <p>\n      Et m\u00e5nedsoverblik hj\u00e6lper dig med at f\u00f8lge din \u00f8konomi m\u00e5ned for m\u00e5ned. N\u00e5r du kan se dine tal samlet \u00e9t sted, bliver det lettere at forst\u00e5, om din privat\u00f8konomi g\u00e5r i den rigtige retning. I NordBalance bliver dit m\u00e5nedsoverblik lavet ud fra de budgetter, du allerede har gemt, s\u00e5 du ikke skal indtaste de samme oplysninger flere gange.\n    <\/p>\n    <p>\n      Med et m\u00e5nedsoverblik kan du sammenligne indkomst, udgifter, opsparing, r\u00e5dighedsbel\u00f8b og \u00f8konomi-score. Hvis dine udgifter falder fra m\u00e5ned til m\u00e5ned, kan du hurtigt se, at dine \u00e6ndringer virker. Hvis din opsparing stiger, kan du f\u00f8lge, hvordan sm\u00e5 forbedringer skaber mere \u00f8konomisk ro. Hvis dit r\u00e5dighedsbel\u00f8b falder, kan m\u00e5nedsoverblikket hj\u00e6lpe dig med at opdage problemet tidligt.\n    <\/p>\n\n    <h2>Hvorfor er et m\u00e5nedsoverblik vigtigt?<\/h2>\n    <p>\n      Mange mennesker laver et budget, men glemmer at f\u00f8lge udviklingen bagefter. Et budget er f\u00f8rst rigtig st\u00e6rkt, n\u00e5r du kan se, om det bliver bedre over tid. Et m\u00e5nedsoverblik g\u00f8r det muligt at se m\u00f8nstre. Du kan opdage, om madbudgettet stiger, om abonnementer fylder mere, eller om g\u00e6lden p\u00e5virker \u00f8konomien for meget.\n    <\/p>\n    <p>\n      NordBalance viser m\u00e5nedsoverblik med grafer og tydelige tal. Det betyder, at brugeren ikke kun ser et enkelt \u00f8jebliksbillede, men hele udviklingen i \u00f8konomien. Det er is\u00e6r vigtigt, hvis m\u00e5let er at spare mere op, f\u00e5 bedre styr p\u00e5 faste udgifter eller reducere g\u00e6ld.\n    <\/p>\n\n    <h2>Hvordan forbedrer du din \u00f8konomi m\u00e5ned for m\u00e5ned?<\/h2>\n    <p>\n      For at forbedre din \u00f8konomi m\u00e5ned for m\u00e5ned skal du f\u00f8rst kende dine tal. N\u00e5r m\u00e5nedsoverblik viser dine st\u00f8rste \u00e6ndringer, kan du v\u00e6lge \u00e9n ting at forbedre ad gangen. Det kan v\u00e6re at reducere madbudgettet, gennemg\u00e5 forsikringer, opsige abonnementer eller l\u00e6gge lidt ekstra til opsparing.\n    <\/p>\n    <p>\n      En god metode er at sammenligne den seneste m\u00e5ned med den forrige m\u00e5ned. Hvis dine udgifter er steget, kan du unders\u00f8ge hvorfor. Hvis din \u00f8konomi-score er faldet, kan du se hvilke poster der p\u00e5virker scoren. Hvis din opsparing er steget, kan du forts\u00e6tte med de gode vaner.\n    <\/p>\n\n    <h2>F\u00f8lg din \u00f8konomi-score over tid<\/h2>\n    <p>\n      Din \u00f8konomi-score g\u00f8r m\u00e5nedsoverblik nemmere at forst\u00e5. I stedet for kun at kigge p\u00e5 mange forskellige tal, f\u00e5r du en samlet vurdering af din \u00f8konomiske sundhed. Scoren tager h\u00f8jde for indkomst, udgifter, opsparing og r\u00e5dighedsbel\u00f8b. N\u00e5r scoren stiger, er det et tegn p\u00e5, at \u00f8konomien bliver st\u00e6rkere.\n    <\/p>\n    <p>\n      M\u00e5nedsoverblik i NordBalance er derfor ikke kun en tabel. Det er et v\u00e6rkt\u00f8j, der hj\u00e6lper dig med at tage bedre beslutninger og skabe en mere stabil privat\u00f8konomi. Med r\u00e5dighedsbel\u00f8b-graf, \u00f8konomi-udvikling og AI-prognose kan brugeren hurtigere se, om der er flere penge tilbage m\u00e5ned for m\u00e5ned.\n    <\/p>\n\n    <h2>Fordele ved m\u00e5nedsoverblik i NordBalance<\/h2>\n    <p>\n      Et m\u00e5nedsoverblik giver bedre overblik, mere motivation og hurtigere reaktion, hvis \u00f8konomien \u00e6ndrer sig. Du kan f\u00f8lge om din opsparing vokser, om udgifterne falder, og om r\u00e5dighedsbel\u00f8bet bliver bedre. Det giver brugeren en klar f\u00f8lelse af fremgang.\n    <\/p>\n    <p>\n      L\u00e6s flere generelle r\u00e5d om budget og privat\u00f8konomi hos\n      <a href=\"https:\/\/www.raadtilpenge.dk\/\" target=\"_blank\" rel=\"noopener\">R\u00e5d til Penge<\/a>.\n    <\/p>\n  <\/section>\n\n<\/div>\n\n<style>\n.entry-content,\n.wp-block-post-content,\n.wp-site-blocks,\n.is-layout-constrained > *,\n.wp-block-group,\n.wp-block-html{max-width:100%!important;width:100%!important}\n\n.nb-month-page{max-width:1500px!important;width:100%!important;margin:auto;padding:30px;font-family:Inter,Arial,sans-serif;background:#f5f7fb;border-radius:24px;color:#0f172a;box-sizing:border-box}\n.nb-top{display:flex;justify-content:space-between;align-items:flex-start;gap:20px;margin-bottom:20px}\n.nb-top h1{font-size:44px;margin:0;font-weight:900}\n.nb-top p{color:#64748b;font-size:18px;margin:8px 0 0;line-height:1.6}\n.logged-user{margin-top:10px;font-weight:900;color:#2563eb}\n.logout-btn{background:#0f172a;color:white;padding:14px 22px;border-radius:14px;font-weight:900;border:none;cursor:pointer}\n.nb-menu{display:flex;gap:12px;flex-wrap:wrap;background:white;padding:15px;border-radius:18px;margin-bottom:25px;box-shadow:0 4px 18px rgba(0,0,0,.05)}\n.nb-menu a{text-decoration:none;color:#0f172a;font-weight:900;background:#f1f5f9;padding:14px 18px;border-radius:12px}\n.nb-menu a:hover,.nb-menu a.active{background:#dbeafe;color:#1d4ed8}\n\n.hero{display:grid;grid-template-columns:1.5fr 260px;gap:25px;align-items:center;background:linear-gradient(135deg,#0f172a,#2563eb);color:white;padding:38px;border-radius:28px;margin-bottom:25px}\n.hero span{display:inline-block;background:rgba(255,255,255,.15);padding:9px 14px;border-radius:999px;font-weight:900;margin-bottom:15px}\n.hero h2{font-size:42px;line-height:1.1;margin:0 0 12px;font-weight:900}\n.hero p{font-size:18px;color:#dbeafe;line-height:1.6;margin:0}\n.hero img{width:100%;max-width:240px;border-radius:22px;background:white;padding:8px}\n\n.status-box{display:flex;justify-content:space-between;gap:12px;align-items:center;background:white;padding:18px 22px;border-radius:18px;margin-bottom:25px;border-left:7px solid #2563eb;box-shadow:0 4px 18px rgba(0,0,0,.05)}\n.status-box strong{font-size:20px}\n.status-box span{color:#475569;font-weight:800}\n.status-box.success{border-left-color:#22c55e;background:#f0fdf4}\n.status-box.warning{border-left-color:#f97316;background:#fff7ed}\n.status-box.error{border-left-color:#ef4444;background:#fef2f2}\n\n.summary-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:18px;margin-bottom:25px}\n.summary-card{background:white;padding:22px;border-radius:18px;border:1px solid #e2e8f0;box-shadow:0 4px 18px rgba(0,0,0,.05)}\n.summary-card span{display:block;color:#64748b;font-weight:900;margin-bottom:8px}\n.summary-card strong{font-size:28px}\n.summary-card p{color:#64748b;font-weight:800;margin:10px 0 0;line-height:1.4}\n.summary-card.green strong{color:#16a34a}\n.up{color:#16a34a!important}\n.down{color:#dc2626!important}\n.neutral{color:#64748b!important}\n\n.dashboard-grid{display:grid;grid-template-columns:1fr 1fr;gap:25px;margin-bottom:25px}\n.full-chart{grid-column:1\/-1}\n.chart-card,.analysis-card,.table-card,.ai-box,.seo-box,.progress-box,.forecast-card{background:white;padding:28px;border-radius:22px;box-shadow:0 4px 20px rgba(0,0,0,.05)}\n.chart-card h2,.analysis-card h2,.table-card h2,.ai-box h2,.seo-box h2,.progress-box h2,.forecast-card h2{margin-top:0;font-size:28px}\n.chart-card p,.analysis-card p,.ai-box p,.seo-box p,.progress-box p,.forecast-card p{font-size:17px;line-height:1.75;color:#475569}\n.analysis-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:18px;margin-bottom:25px}\n.analysis-card div{font-size:17px;line-height:1.7;color:#475569}\n.table-card{margin-bottom:25px}\n.table-wrap{overflow-x:auto}\ntable{width:100%;border-collapse:collapse}\nth,td{text-align:left;padding:14px;border-bottom:1px solid #e2e8f0;white-space:nowrap}\nth{background:#f8fafc;color:#475569;font-weight:900}\ntd{font-weight:800}\n.ai-box{background:#ecfeff;border-left:7px solid #06b6d4;margin-bottom:25px}\n\n.progress-box{display:grid;grid-template-columns:1fr 1.2fr;gap:22px;align-items:center;margin-bottom:25px;border-left:7px solid #2563eb}\n.progress-label{display:inline-block;background:#dbeafe;color:#1d4ed8;padding:8px 12px;border-radius:999px;font-weight:900;margin-bottom:12px}\n.progress-items{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:12px}\n.progress-item{padding:14px;border-radius:14px;background:#f8fafc;font-weight:900;line-height:1.45}\n.progress-item.up{background:#dcfce7;color:#166534}.progress-item.down{background:#fee2e2;color:#991b1b}.progress-item.neutral{background:#f1f5f9;color:#475569}\n.forecast-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-bottom:25px}\n.forecast-card{border-left:7px solid #7c3aed}\n\n.seo-box{line-height:1.75}\n.seo-box a{color:#2563eb;font-weight:900}\n\n\n.delete-month-btn{background:#dc2626;color:white;border:none;padding:9px 13px;border-radius:10px;font-weight:900;cursor:pointer;white-space:nowrap}\n.delete-month-btn:hover{background:#b91c1c}\n\n@media(max-width:900px){\n.progress-box,.forecast-grid{grid-template-columns:1fr}\n.nb-month-page{padding:18px;border-radius:16px}\n.nb-top{flex-direction:column}\n.nb-top h1{font-size:34px}\n.logout-btn{width:100%}\n.nb-menu{display:grid;grid-template-columns:1fr}\n.nb-menu a{text-align:center}\n.hero{grid-template-columns:1fr;padding:25px}\n.hero h2{font-size:30px}\n.hero img{max-width:170px;margin:auto}\n.dashboard-grid{grid-template-columns:1fr}\n.status-box{flex-direction:column;align-items:flex-start}\n.chart-card,.analysis-card,.table-card,.ai-box,.seo-box{padding:22px}\n}\n<\/style>\n\n<script>\nconst SUPABASE_URL=\"https:\/\/vmcpmdcbzatavfkwdcuz.supabase.co\";\nconst SUPABASE_KEY=\"sb_publishable_ODGTPniESClcPb8E2alCQQ_3tadLNmM\";\nconst supabaseClient=window.supabase.createClient(SUPABASE_URL,SUPABASE_KEY);\n\nlet currentUser=null;\nlet scoreChart=null;\nlet moneyChart=null;\nlet disposableChart=null;\n\nasync function logoutUser(){\n  await supabaseClient.auth.signOut();\n  window.location.href=\"https:\/\/nordbalance.dk\/?page_id=40\";\n}\n\nfunction kr(value){\n  return new Intl.NumberFormat(\"da-DK\",{style:\"currency\",currency:\"DKK\",maximumFractionDigits:0}).format(Number(value)||0);\n}\n\nfunction setText(id,text){\n  const el=document.getElementById(id);\n  if(el) el.textContent=text;\n}\n\nfunction setHtml(id,html){\n  const el=document.getElementById(id);\n  if(el) el.innerHTML=html;\n}\n\nfunction num(row,key){\n  return Number(row?.[key])||0;\n}\n\nfunction monthName(row){\n  if(row.month) return row.month;\n  if(row.m\u00e5ned) return row.m\u00e5ned;\n  if(row.created_at){\n    return new Date(row.created_at).toLocaleDateString(\"da-DK\",{month:\"long\",year:\"numeric\"});\n  }\n  return \"Ukendt m\u00e5ned\";\n}\n\nfunction calculateScore(income,expenses,savings,disposable){\n  let score=50;\n  if(income>0){\n    const expenseRate=expenses\/income;\n    const savingRate=savings\/income;\n    if(disposable>=0) score+=10;\n    if(expenseRate<0.85) score+=10;\n    if(expenseRate<0.70) score+=10;\n    if(savingRate>=0.05) score+=10;\n    if(savingRate>=0.10) score+=10;\n  }\n  if(disposable<0) score-=25;\n  return Math.max(0,Math.min(100,Math.round(score)));\n}\n\nfunction parseBudget(row){\n  const income=num(row,\"samlet_indkomst\") || num(row,\"income\")+num(row,\"indkomst2\") || num(row,\"income\");\n  const expenses=\n    num(row,\"housing\")+\n    num(row,\"food\")+\n    num(row,\"transport\")+\n    num(row,\"subs\")+\n    num(row,\"insurance\")+\n    num(row,\"utilities\")+\n    num(row,\"phone\")+\n    num(row,\"debt\")+\n    num(row,\"leisure\")+\n    num(row,\"other\");\n\n  const savings=num(row,\"savings\");\n  const disposable=num(row,\"r\u00e5dighedsbel\u00f8b\") || income-expenses-savings;\n  let score=num(row,\"score\");\n  if(!score || score<0 || score>100){\n    score=calculateScore(income,expenses,savings,disposable);\n  }\n\n  return {\n    id:row.id || \"\",\n    month:monthName(row),\n    created_at:row.created_at || \"\",\n    income,\n    expenses,\n    savings,\n    disposable,\n    score\n  };\n}\n\nfunction diffText(current,previous,type=\"money\",positiveGood=true){\n  if(!previous && previous!==0) return \"Ingen tidligere m\u00e5ned endnu.\";\n  const diff=current-previous;\n  if(diff===0) return \"U\u00e6ndret fra sidste m\u00e5ned.\";\n  const good=positiveGood ? diff>0 : diff<0;\n  const cls=good ? \"up\" : \"down\";\n  const sign=diff>0 ? \"+\" : \"-\";\n  const value=type===\"score\" ? Math.abs(diff)+\" point\" : kr(Math.abs(diff));\n  return `<span class=\"${cls}\">${sign}${value} fra sidste m\u00e5ned<\/span>`;\n}\n\nasync function checkUser(){\n  const {data,error}=await supabaseClient.auth.getUser();\n  if(error || !data?.user){\n    window.location.href=\"https:\/\/nordbalance.dk\/?page_id=40\";\n    return null;\n  }\n  currentUser=data.user;\n  setText(\"loggedUser\",\"Logget ind som: \"+currentUser.email);\n  return currentUser;\n}\n\nasync function fetchBudgets(){\n  if(!currentUser) return [];\n\n  let {data,error}=await supabaseClient\n    .from(\"budgets\")\n    .select(\"*\")\n    .eq(\"user_id\",currentUser.id)\n    .order(\"created_at\",{ascending:true});\n\n  if(error){\n    console.warn(\"Budget user_id fejl:\",error);\n  }\n\n  if((!data || data.length===0) && currentUser.email){\n    const fallback=await supabaseClient\n      .from(\"budgets\")\n      .select(\"*\")\n      .eq(\"user_email\",currentUser.email)\n      .order(\"created_at\",{ascending:true});\n\n    data=fallback.data;\n    error=fallback.error;\n\n    if(error){\n      console.warn(\"Budget user_email fejl:\",error);\n    }\n  }\n\n  return (data||[]).map(parseBudget);\n}\n\nfunction setStatus(title,text,type=\"info\"){\n  const box=document.getElementById(\"monthStatus\");\n  if(!box) return;\n  box.className=\"status-box \"+type;\n  box.innerHTML=`<strong>${title}<\/strong><span>${text}<\/span>`;\n}\n\nfunction renderSummary(rows){\n  const latest=rows[rows.length-1];\n  const prev=rows.length>1 ? rows[rows.length-2] : null;\n\n  setText(\"latestMonth\",latest.month);\n  setText(\"latestScore\",latest.score+\" \/ 100\");\n  setText(\"latestExpenses\",kr(latest.expenses));\n  setText(\"latestSavings\",kr(latest.savings));\n  setText(\"latestDisposable\",kr(latest.disposable));\n\n  setHtml(\"scoreDiff\",prev ? diffText(latest.score,prev.score,\"score\",true) : \"Ingen tidligere m\u00e5ned endnu.\");\n  setHtml(\"expenseDiff\",prev ? diffText(latest.expenses,prev.expenses,\"money\",false) : \"Ingen tidligere m\u00e5ned endnu.\");\n  setHtml(\"savingDiff\",prev ? diffText(latest.savings,prev.savings,\"money\",true) : \"Ingen tidligere m\u00e5ned endnu.\");\n  setHtml(\"disposableDiff\",prev ? diffText(latest.disposable,prev.disposable,\"money\",true) : \"Ingen tidligere m\u00e5ned endnu.\");\n}\n\nfunction renderCharts(rows){\n  const labels=rows.map(r=>r.month);\n  const scores=rows.map(r=>r.score);\n  const income=rows.map(r=>r.income);\n  const expenses=rows.map(r=>r.expenses);\n  const savings=rows.map(r=>r.savings);\n  const disposable=rows.map(r=>r.disposable);\n\n  if(scoreChart) scoreChart.destroy();\n  if(moneyChart) moneyChart.destroy();\n  if(disposableChart) disposableChart.destroy();\n\n  scoreChart=new Chart(document.getElementById(\"scoreChart\"),{\n    type:\"line\",\n    data:{\n      labels,\n      datasets:[{\n        label:\"\u00d8konomi-score\",\n        data:scores,\n        tension:.35\n      }]\n    },\n    options:{\n      responsive:true,\n      plugins:{legend:{display:true}},\n      scales:{y:{beginAtZero:true,max:100}}\n    }\n  });\n\n  moneyChart=new Chart(document.getElementById(\"moneyChart\"),{\n    type:\"bar\",\n    data:{\n      labels,\n      datasets:[\n        {label:\"Indkomst\",data:income},\n        {label:\"Udgifter\",data:expenses},\n        {label:\"Opsparing\",data:savings}\n      ]\n    },\n    options:{\n      responsive:true,\n      plugins:{legend:{display:true}},\n      scales:{y:{beginAtZero:true}}\n    }\n  });\n\n  disposableChart=new Chart(document.getElementById(\"disposableChart\"),{\n    type:\"line\",\n    data:{\n      labels,\n      datasets:[{\n        label:\"R\u00e5dighedsbel\u00f8b\",\n        data:disposable,\n        tension:.35\n      }]\n    },\n    options:{\n      responsive:true,\n      plugins:{legend:{display:true}},\n      scales:{y:{beginAtZero:true}}\n    }\n  });\n}\n\nfunction renderProgressAndForecast(rows){\n  const latest=rows[rows.length-1];\n  const prev=rows.length>1 ? rows[rows.length-2] : null;\n\n  if(!prev){\n    setText(\"progressTitle\",\"Gem \u00e9n m\u00e5ned mere\");\n    setText(\"progressText\",\"N\u00e5r der er mindst 2 m\u00e5neder gemt, kan NordBalance vise pr\u00e6cis om \u00f8konomien bliver bedre.\");\n    setHtml(\"progressItems\",'<div class=\"progress-item neutral\">Ingen tidligere m\u00e5ned endnu.<\/div>');\n    setText(\"forecastText\",\"Gem mindst 2 m\u00e5neder for at f\u00e5 en enkel 6-m\u00e5neders prognose.\");\n    setText(\"nextGoalText\",\"N\u00e6ste m\u00e5l: Gem n\u00e6ste m\u00e5neds budget, s\u00e5 udviklingen kan m\u00e5les.\");\n    return;\n  }\n\n  const scoreDiff=latest.score-prev.score;\n  const expenseDiff=latest.expenses-prev.expenses;\n  const savingDiff=latest.savings-prev.savings;\n  const disposableDiff=latest.disposable-prev.disposable;\n\n  const positives=[scoreDiff>0, expenseDiff<0, savingDiff>0, disposableDiff>0].filter(Boolean).length;\n  if(positives>=3){\n    setText(\"progressTitle\",\"Din \u00f8konomi er forbedret \u2705\");\n    setText(\"progressText\",\"Flere af dine vigtigste n\u00f8gletal g\u00e5r i den rigtige retning siden sidste m\u00e5ned.\");\n  }else if(positives>=2){\n    setText(\"progressTitle\",\"Din \u00f8konomi er stabil \ud83d\udc4d\");\n    setText(\"progressText\",\"Nogle tal er forbedret, men der er stadig plads til at optimere n\u00e6ste m\u00e5ned.\");\n  }else{\n    setText(\"progressTitle\",\"Din \u00f8konomi kr\u00e6ver fokus \u26a0\ufe0f\");\n    setText(\"progressText\",\"Flere n\u00f8gletal g\u00e5r den forkerte vej. V\u00e6lg \u00e9n post at forbedre n\u00e6ste m\u00e5ned.\");\n  }\n\n  const item=(label,diff,type,positiveGood)=>{\n    const good=positiveGood ? diff>0 : diff<0;\n    const cls=diff===0 ? \"neutral\" : (good ? \"up\" : \"down\");\n    const sign=diff>0 ? \"+\" : diff<0 ? \"-\" : \"\";\n    const value=type===\"score\" ? Math.abs(diff)+\" point\" : kr(Math.abs(diff));\n    return `<div class=\"progress-item ${cls}\">${label}: ${sign}${value}<\/div>`;\n  };\n\n  setHtml(\"progressItems\",\n    item(\"Score\",scoreDiff,\"score\",true)+\n    item(\"Udgifter\",expenseDiff,\"money\",false)+\n    item(\"Opsparing\",savingDiff,\"money\",true)+\n    item(\"R\u00e5dighedsbel\u00f8b\",disposableDiff,\"money\",true)\n  );\n\n  const months=6;\n  const projectedScore=Math.max(0,Math.min(100,Math.round(latest.score+(scoreDiff*months))));\n  const projectedSavings=Math.max(0,Math.round(latest.savings+(savingDiff*months)));\n  const projectedDisposable=Math.round(latest.disposable+(disposableDiff*months));\n\n  setText(\"forecastText\",\"Hvis udviklingen forts\u00e6tter i samme retning, kan din score om 6 m\u00e5neder v\u00e6re ca. \"+projectedScore+\"\/100, opsparing ca. \"+kr(projectedSavings)+\" og r\u00e5dighedsbel\u00f8b ca. \"+kr(projectedDisposable)+\". Prognosen er vejledende og baseret p\u00e5 de seneste 2 m\u00e5neder.\");\n\n  if(latest.disposable<0){\n    setText(\"nextGoalText\",\"N\u00e6ste m\u00e5l: F\u00e5 r\u00e5dighedsbel\u00f8bet i plus ved at gennemg\u00e5 mad, abonnementer og andre variable udgifter.\");\n  }else if(latest.savings<=0){\n    setText(\"nextGoalText\",\"N\u00e6ste m\u00e5l: Start med fast opsparing, selv et mindre bel\u00f8b hver m\u00e5ned kan skabe fremgang.\");\n  }else if(expenseDiff>0){\n    setText(\"nextGoalText\",\"N\u00e6ste m\u00e5l: Stop udgiftsstigningen og v\u00e6lg \u00e9n post, der skal ned n\u00e6ste m\u00e5ned.\");\n  }else{\n    setText(\"nextGoalText\",\"N\u00e6ste m\u00e5l: \u00d8g buffer eller opsparing, fordi \u00f8konomien allerede bev\u00e6ger sig i en god retning.\");\n  }\n}\n\nfunction renderTable(rows){\n  let html=\"\";\n  rows.slice().reverse().forEach(r=>{\n    const safeId=String(r.id || \"\").replace(\/'\/g,\"\\\\'\");\n    const deleteButton=r.id ? `<button class=\"delete-month-btn\" type=\"button\" onclick=\"deleteBudget('${safeId}')\">\ud83d\uddd1\ufe0f Slet<\/button>` : \"-\";\n\n    html+=`\n      <tr>\n        <td>${r.month}<\/td>\n        <td>${kr(r.income)}<\/td>\n        <td>${kr(r.expenses)}<\/td>\n        <td>${kr(r.savings)}<\/td>\n        <td>${kr(r.disposable)}<\/td>\n        <td>${r.score} \/ 100<\/td>\n        <td>${deleteButton}<\/td>\n      <\/tr>`;\n  });\n  setHtml(\"monthTable\",html);\n}\n\nfunction renderAnalysis(rows){\n  const latest=rows[rows.length-1];\n  const prev=rows.length>1 ? rows[rows.length-2] : null;\n\n  if(!prev){\n    setHtml(\"scoreAnalysis\",\"Gem mindst to m\u00e5neder for at se om din \u00f8konomi-score bliver bedre.\");\n    setHtml(\"savingAnalysis\",\"Gem mindst to m\u00e5neder for at se udviklingen i opsparing.\");\n    setHtml(\"changeList\",\"Der mangler historik til en fuld m\u00e5nedsanalyse.\");\n    setText(\"aiAdvice\",\"Du har kun \u00e9n m\u00e5ned gemt. Gem budgettet igen n\u00e6ste m\u00e5ned, s\u00e5 NordBalance kan vise udviklingen i dit m\u00e5nedsoverblik.\");\n    return;\n  }\n\n  const scoreDiff=latest.score-prev.score;\n  const expenseDiff=latest.expenses-prev.expenses;\n  const savingDiff=latest.savings-prev.savings;\n  const disposableDiff=latest.disposable-prev.disposable;\n\n  let scoreHtml=\"\";\n  if(scoreDiff>0) scoreHtml=\"\u2705 Din \u00f8konomi-score er steget med \"+scoreDiff+\" point. Det tyder p\u00e5, at din \u00f8konomi bliver bedre.\";\n  else if(scoreDiff<0) scoreHtml=\"\u26a0\ufe0f Din \u00f8konomi-score er faldet med \"+Math.abs(scoreDiff)+\" point. Gennemg\u00e5 udgifter og opsparing.\";\n  else scoreHtml=\"\u2796 Din \u00f8konomi-score er u\u00e6ndret fra sidste m\u00e5ned.\";\n\n  let savingHtml=\"\";\n  if(savingDiff>0) savingHtml=\"\ud83d\udc9a Din opsparing er steget med \"+kr(savingDiff)+\". Forts\u00e6t den gode udvikling.\";\n  else if(savingDiff<0) savingHtml=\"\u26a0\ufe0f Din opsparing er faldet med \"+kr(Math.abs(savingDiff))+\". Overvej at g\u00f8re opsparing mere fast.\";\n  else savingHtml=\"\u2796 Din opsparing er u\u00e6ndret.\";\n\n  let changes=[\n    \"Score: \"+(scoreDiff>0 ? \"+\" : \"\")+scoreDiff+\" point\",\n    \"Udgifter: \"+(expenseDiff>0 ? \"+\" : \"\")+kr(expenseDiff).replace(\"kr.\",\"kr.\"),\n    \"Opsparing: \"+(savingDiff>0 ? \"+\" : \"\")+kr(savingDiff).replace(\"kr.\",\"kr.\"),\n    \"R\u00e5dighedsbel\u00f8b: \"+(disposableDiff>0 ? \"+\" : \"\")+kr(disposableDiff).replace(\"kr.\",\"kr.\")\n  ];\n\n  setHtml(\"scoreAnalysis\",scoreHtml);\n  setHtml(\"savingAnalysis\",savingHtml);\n  setHtml(\"changeList\",\"<ul><li>\"+changes.join(\"<\/li><li>\")+\"<\/li><\/ul>\");\n\n  let advice=\"\";\n  if(scoreDiff>0 && savingDiff>=0 && expenseDiff<=0){\n    advice=\"Din \u00f8konomi g\u00e5r i den rigtige retning. Udgifterne falder eller er stabile, og opsparingen holder niveau. N\u00e6ste m\u00e5l kan v\u00e6re at \u00f8ge buffer eller betale ekstra af p\u00e5 dyr g\u00e6ld.\";\n  }else if(expenseDiff>0){\n    advice=\"Dine udgifter er steget siden sidste m\u00e5ned. Gennemg\u00e5 is\u00e6r mad, abonnementer, transport og andre udgifter. M\u00e5let b\u00f8r v\u00e6re at f\u00e5 udgifterne ned igen n\u00e6ste m\u00e5ned.\";\n  }else if(savingDiff<0){\n    advice=\"Din opsparing er faldet. Pr\u00f8v at s\u00e6tte en fast opsparing f\u00f8rst p\u00e5 m\u00e5neden, s\u00e5 pengene ikke forsvinder i l\u00f8bende forbrug.\";\n  }else{\n    advice=\"Din \u00f8konomi er nogenlunde stabil. Brug m\u00e5nedsoverblik til at v\u00e6lge \u00e9n forbedring for n\u00e6ste m\u00e5ned.\";\n  }\n\n  setText(\"aiAdvice\",advice);\n}\n\nasync function deleteBudget(budgetId){\n  if(!currentUser){\n    alert(\"Du skal v\u00e6re logget ind for at slette en m\u00e5ned.\");\n    return;\n  }\n\n  if(!budgetId){\n    alert(\"M\u00e5neden mangler ID og kan ikke slettes.\");\n    return;\n  }\n\n  const ok=confirm(\"Er du sikker p\u00e5, at du vil slette denne gemte m\u00e5ned? Handlingen kan ikke fortrydes.\");\n  if(!ok){return;}\n\n  setStatus(\"Sletter m\u00e5ned\",\"Vi sletter den valgte m\u00e5ned fra Supabase...\",\"info\");\n\n  let {error}=await supabaseClient\n    .from(\"budgets\")\n    .delete()\n    .eq(\"id\",budgetId)\n    .eq(\"user_id\",currentUser.id);\n\n  if(error){\n    console.error(\"Slet via user_id fejlede:\",error);\n\n    if(currentUser.email){\n      const fallback=await supabaseClient\n        .from(\"budgets\")\n        .delete()\n        .eq(\"id\",budgetId)\n        .eq(\"user_email\",currentUser.email);\n\n      error=fallback.error;\n    }\n  }\n\n  if(error){\n    console.error(\"Kunne ikke slette budget:\",error);\n    alert(\"Kunne ikke slette m\u00e5neden. Tjek Supabase RLS-politik for delete p\u00e5 budgets.\");\n    setStatus(\"Kunne ikke slette\",\"M\u00e5neden blev ikke slettet. Tjek Supabase-reglerne.\",\"error\");\n    return;\n  }\n\n  const rows=await fetchBudgets();\n\n  if(!rows.length){\n    setStatus(\"Ingen m\u00e5neder tilbage\",\"Alle gemte m\u00e5neder er slettet.\",\"warning\");\n    setHtml(\"monthTable\",\"<tr><td colspan='7'>Ingen budgetdata fundet.<\/td><\/tr>\");\n    setText(\"latestMonth\",\"-\");\n    setText(\"latestScore\",\"0 \/ 100\");\n    setText(\"latestExpenses\",kr(0));\n    setText(\"latestSavings\",kr(0));\n    setText(\"latestDisposable\",kr(0));\n    return;\n  }\n\n  renderSummary(rows);\n  renderCharts(rows);\n  renderProgressAndForecast(rows);\n  renderTable(rows);\n  renderAnalysis(rows);\n  setStatus(\"M\u00e5ned slettet\",\"Den valgte m\u00e5ned er slettet fra Supabase.\",\"success\");\n}\n\nasync function initMonthOverview(){\n  const user=await checkUser();\n  if(!user) return;\n\n  setStatus(\"Henter m\u00e5nedsoverblik\",\"Vi henter dine budgetdata...\",\"info\");\n\n  const rows=await fetchBudgets();\n\n  if(!rows.length){\n    setStatus(\"Intet budget fundet\",\"G\u00e5 til Mit Budget og gem dit f\u00f8rste budget. Derefter kan m\u00e5nedsoverblik vise udviklingen.\",\"warning\");\n    setHtml(\"monthTable\",\"<tr><td colspan='7'>Ingen budgetdata fundet.<\/td><\/tr>\");\n    return;\n  }\n\n  renderSummary(rows);\n  renderCharts(rows);\n  renderProgressAndForecast(rows);\n  renderTable(rows);\n  renderAnalysis(rows);\n\n  if(rows.length<2){\n    setStatus(\"M\u00e5nedsoverblik indl\u00e6st\",\"Gem mindst to m\u00e5neder for at f\u00e5 fuld udviklingsanalyse.\",\"warning\");\n  }else{\n    setStatus(\"M\u00e5nedsoverblik indl\u00e6st\",\"Din \u00f8konomi er nu vist m\u00e5ned for m\u00e5ned.\",\"success\");\n  }\n}\n\nwindow.addEventListener(\"load\",initMonthOverview);\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>M\u00e5nedsoverblik M\u00e5nedsoverblik giver dig et samlet billede af din \u00f8konomi m\u00e5ned for m\u00e5ned. Tjekker login&#8230; Log ud \ud83d\udcca Mit Budget \ud83d\udcb0 Opsparing \ud83d\udcc8 \u00d8konomi-score \ud83d\udcc5 M\u00e5nedsoverblik \ud83e\udde0 Smart Budget Planner \ud83e\udd16 AI Hj\u00e6lp \u2699\ufe0f Min Profil M\u00e5nedsoverblik over din privat\u00f8konomi M\u00e5nedsoverblik: 7 m\u00e5der at f\u00f8lge din \u00f8konomi m\u00e5ned for m\u00e5ned NordBalance henter dine gemte budgetter [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-493","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/nordbalance.dk\/index.php?rest_route=\/wp\/v2\/pages\/493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nordbalance.dk\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/nordbalance.dk\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/nordbalance.dk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nordbalance.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=493"}],"version-history":[{"count":8,"href":"https:\/\/nordbalance.dk\/index.php?rest_route=\/wp\/v2\/pages\/493\/revisions"}],"predecessor-version":[{"id":510,"href":"https:\/\/nordbalance.dk\/index.php?rest_route=\/wp\/v2\/pages\/493\/revisions\/510"}],"wp:attachment":[{"href":"https:\/\/nordbalance.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}