foxygit / FORTIS Log in
commit 03f1303b2335dfbce75cefcf73f18950da291c70
Author:     jens <jens.se@icloud.com>
AuthorDate: Wed Apr 29 13:54:28 2026 +0200
Commit:     jens <jens.se@icloud.com>
CommitDate: Thu Apr 30 07:31:41 2026 +0200

    Initial commit — FORTIS träningsapp HTML-prototyp (Fas 1 + Fas 2)

    Fullt fungerande prototyp med splash, onboarding, dashboard, schema,
    aktiv träning, övningsbibliotek (75 övningar + egna övningar), kostlogg,
    progressionsgraf, achievements, tema-system (5 teman) och profil.
---
 FORTIS-app.html          | 1701 ++++++++++++++++++++++++++++++++++++++++++++++
 FORTIS_HANDOFF.md        |  380 +++++++++++
 README.md                |  558 +++++++++++++++
 Träningsapp_Planering.md |  510 ++++++++++++++
 4 files changed, 3149 insertions(+)

diff --git a/FORTIS-app.html b/FORTIS-app.html
new file mode 100644
index 0000000..5fed111
--- /dev/null
+++ b/FORTIS-app.html
@@ -0,0 +1,1701 @@
+<!DOCTYPE html>
+<html lang="sv">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>FORTIS</title>
+<style>
+*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent;font-family:'Helvetica Neue',Arial,sans-serif}
+:root{
+  --accent:#E85D26;
+  --accent2:#2A6AE8;
+  --accent-light:#FEF0EB;
+  --bg:#F2F1ED;
+  --card:#FFFFFF;
+  --text:#141414;
+  --muted:#888880;
+  --border:rgba(0,0,0,0.09);
+  --nav:#FFFFFF;
+  --header:#141414;
+  --header-text:#FFFFFF;
+  --outer:#E8E6E0;
+  --nav-h:66px;
+  --radius:14px;
+  --radius-sm:10px;
+}
+html,body{height:100%;background:var(--outer)}
+#root{max-width:420px;margin:0 auto;min-height:100vh;background:var(--bg);position:relative;overflow:hidden;box-shadow:0 0 40px rgba(0,0,0,0.15);transition:background 0.3s}
+
+/* ── SPLASH ─────────────────────────────── */
+#splash{position:absolute;inset:0;background:#0F0F0F;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:100}
+.splash-ring{position:relative;width:140px;height:140px;margin-bottom:32px}
+.splash-ring svg{animation:spin 3s linear infinite}
+@keyframes spin{to{transform:rotate(360deg)}}
+.splash-logo{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
+.splash-name{font-size:32px;font-weight:800;letter-spacing:0.12em;color:#FFF;margin-bottom:2px}
+.splash-sub{font-size:10px;letter-spacing:0.25em;color:#666;text-transform:uppercase}
+.splash-progress{position:absolute;bottom:48px;left:48px;right:48px;height:2px;background:#222;border-radius:1px;overflow:hidden}
+.splash-fill{height:100%;background:var(--accent);border-radius:1px;width:0;transition:width 0.1s linear}
+
+/* ── ONBOARDING ──────────────────────────── */
+#onboarding{position:absolute;inset:0;background:#FFF;overflow-y:auto;display:none}
+.ob-header{padding:56px 28px 24px;background:#FFF}
+.ob-steps{display:flex;gap:6px;margin-bottom:28px}
+.ob-step{height:3px;flex:1;border-radius:2px;background:#EAEAEA;transition:background 0.3s}
+.ob-step.done{background:var(--accent)}
+.ob-title{font-size:26px;font-weight:800;color:var(--text);line-height:1.2;margin-bottom:6px}
+.ob-desc{font-size:14px;color:var(--muted);line-height:1.5}
+.ob-body{padding:0 28px 120px}
+.field{margin-bottom:18px}
+.field label{display:block;font-size:12px;font-weight:600;letter-spacing:0.06em;color:var(--muted);text-transform:uppercase;margin-bottom:7px}
+.field input,.field select{width:100%;padding:14px 16px;border:1.5px solid #E8E8E8;border-radius:var(--radius-sm);font-size:16px;color:var(--text);background:#FFF;-webkit-appearance:none;outline:none;transition:border-color 0.2s}
+.field input:focus,.field select:focus{border-color:var(--accent)}
+.field-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
+.radio-group{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
+.radio-opt{padding:12px 8px;border:1.5px solid #E8E8E8;border-radius:var(--radius-sm);text-align:center;font-size:13px;cursor:pointer;transition:all 0.2s;color:var(--text)}
+.radio-opt.active{border-color:var(--accent);background:var(--accent-light);color:var(--accent);font-weight:600}
+.macro-preview{background:#F7F7F5;border-radius:var(--radius);padding:20px;margin-top:8px}
+.macro-row{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid #EAEAEA}
+.macro-row:last-child{border-bottom:none}
+.macro-name{font-size:14px;color:var(--muted)}
+.macro-val{font-size:18px;font-weight:700;color:var(--text)}
+.macro-unit{font-size:12px;color:var(--muted);font-weight:400}
+.ob-footer{position:fixed;bottom:0;left:50%;transform:translateX(-50%);width:100%;max-width:420px;padding:16px 28px 32px;background:#FFF;border-top:1px solid #EAEAEA}
+.btn-primary{width:100%;padding:17px;background:var(--accent);color:#FFF;font-size:16px;font-weight:700;border:none;border-radius:var(--radius);cursor:pointer;letter-spacing:0.02em;transition:opacity 0.2s}
+.btn-primary:active{opacity:0.85}
+.btn-ghost{width:100%;padding:13px;background:none;color:var(--muted);font-size:14px;border:none;cursor:pointer;margin-top:8px}
+.done-screen{text-align:center;padding:48px 28px}
+.done-icon{width:80px;height:80px;background:var(--accent-light);border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 24px;font-size:36px}
+.done-title{font-size:28px;font-weight:800;color:var(--text);margin-bottom:8px}
+.done-sub{font-size:15px;color:var(--muted);line-height:1.6}
+
+/* ── MAIN APP ────────────────────────────── */
+#app{position:absolute;inset:0;display:none;flex-direction:column}
+.screen{flex:1;overflow-y:auto;padding-bottom:calc(var(--nav-h) + 16px)}
+
+/* ── BOTTOM NAV ───────────────────────────  */
+.bottom-nav{position:fixed;bottom:0;left:50%;transform:translateX(-50%);width:100%;max-width:420px;height:var(--nav-h);background:var(--nav);border-top:1px solid var(--border);display:flex;align-items:center;z-index:50;padding:0 8px}
+.nav-item{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 4px;cursor:pointer;border:none;background:none;transition:color 0.2s}
+.nav-icon{font-size:20px;line-height:1}
+.nav-label{font-size:10px;letter-spacing:0.04em;font-weight:500;color:var(--muted)}
+.nav-item.active .nav-label{color:var(--accent)}
+.nav-item.active .nav-icon{filter:none}
+
+/* ── HOME / DASHBOARD ────────────────────── */
+.home-header{padding:52px 22px 20px;background:var(--header)}
+.greeting-sub{font-size:12px;color:#888;letter-spacing:0.08em;text-transform:uppercase;margin-bottom:4px}
+.greeting{font-size:26px;font-weight:800;color:#FFF;line-height:1.2}
+.streak-pill{display:inline-flex;align-items:center;gap:5px;background:#2A2A2A;border-radius:20px;padding:5px 12px;margin-top:12px;font-size:12px;color:#FFF;font-weight:600}
+.home-content{padding:18px 16px}
+.section-title{font-size:12px;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;color:var(--muted);margin-bottom:10px}
+.card{background:var(--card);border-radius:var(--radius);padding:18px;margin-bottom:14px;border:1px solid var(--border)}
+
+/* Calorie Ring */
+.calorie-card{display:flex;align-items:center;gap:20px}
+.ring-wrap{position:relative;flex-shrink:0}
+.ring-wrap svg{transform:rotate(-90deg)}
+.ring-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
+.ring-num{font-size:22px;font-weight:800;color:var(--text)}
+.ring-label{font-size:10px;color:var(--muted);letter-spacing:0.06em;text-transform:uppercase}
+.ring-macros{flex:1}
+.rm-row{margin-bottom:10px}
+.rm-label{display:flex;justify-content:space-between;margin-bottom:4px}
+.rm-name{font-size:12px;color:var(--muted)}
+.rm-val{font-size:12px;font-weight:600;color:var(--text)}
+.rm-bar{height:5px;background:#F0F0EE;border-radius:3px;overflow:hidden}
+.rm-fill{height:100%;border-radius:3px}
+
+/* Water */
+.water-card .section-title{margin-bottom:14px}
+.water-row{display:flex;align-items:center;gap:12px}
+.water-drops{display:flex;gap:5px;flex:1;flex-wrap:wrap}
+.drop{width:22px;height:22px;border-radius:50% 50% 50% 0;transform:rotate(-45deg);background:#E8F4FD;border:1.5px solid #C8E6F8;transition:background 0.2s}
+.drop.filled{background:#2A6AE8;border-color:#2A6AE8}
+.water-btn{padding:8px 14px;border:1.5px solid #2A6AE8;border-radius:8px;color:#2A6AE8;font-size:13px;font-weight:600;background:none;cursor:pointer}
+
+/* Today's workout */
+.workout-card-inner{display:flex;justify-content:space-between;align-items:flex-start}
+.workout-name{font-size:18px;font-weight:800;color:var(--text);margin-bottom:4px}
+.workout-meta{font-size:13px;color:var(--muted)}
+.muscle-badges{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
+.badge{padding:4px 10px;border-radius:20px;font-size:11px;font-weight:600}
+.badge-orange{background:var(--accent-light);color:var(--accent)}
+.badge-blue{background:#EBF0FE;color:#2A6AE8}
+.badge-green{background:#EAFAEE;color:#22A647}
+.btn-start{padding:10px 18px;background:var(--accent);color:#FFF;border:none;border-radius:10px;font-size:14px;font-weight:700;cursor:pointer;white-space:nowrap}
+.btn-start:active{opacity:0.85}
+.no-workout{text-align:center;padding:12px 0;color:var(--muted);font-size:14px}
+
+/* ── SCHEDULE ──────────────────────────────  */
+.sched-header{padding:52px 22px 0;background:var(--header)}
+.sched-title{font-size:24px;font-weight:800;color:#FFF;margin-bottom:18px}
+.week-strip{display:flex;gap:4px;overflow-x:auto;padding-bottom:16px;scrollbar-width:none}
+.week-strip::-webkit-scrollbar{display:none}
+.day-pill{flex-shrink:0;width:46px;height:62px;border-radius:12px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;cursor:pointer;background:rgba(255,255,255,0.1);border:1.5px solid transparent;transition:all 0.2s}
+.day-pill.active{background:#FFF;border-color:#FFF}
+.day-name{font-size:10px;letter-spacing:0.06em;color:rgba(255,255,255,0.6);font-weight:600;text-transform:uppercase}
+.day-num{font-size:18px;font-weight:800;color:rgba(255,255,255,0.9)}
+.day-pill.active .day-name{color:var(--muted)}
+.day-pill.active .day-num{color:var(--text)}
+.day-dot{width:4px;height:4px;border-radius:50%;background:var(--accent)}
+.day-pill.active .day-dot{background:var(--accent)}
+.sched-body{padding:18px 16px}
+.day-title{font-size:20px;font-weight:800;color:var(--text);margin-bottom:14px}
+.workout-block{background:var(--card);border-radius:var(--radius);overflow:hidden;border:1px solid var(--border);margin-bottom:12px}
+.wb-header{padding:14px 16px;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--border)}
+.wb-name{font-size:16px;font-weight:700;color:var(--text)}
+.wb-time{font-size:12px;color:var(--muted)}
+.wb-exercises{padding:12px 16px}
+.wb-ex{display:flex;align-items:center;gap:10px;padding:6px 0;font-size:14px;color:var(--text)}
+.wb-ex-dot{width:6px;height:6px;border-radius:50%;background:var(--accent);flex-shrink:0}
+.wb-ex-detail{color:var(--muted);font-size:12px;margin-left:auto}
+.wb-footer{padding:12px 16px;border-top:1px solid var(--border)}
+.btn-start-full{width:100%;padding:13px;background:var(--accent);color:#FFF;border:none;border-radius:10px;font-size:14px;font-weight:700;cursor:pointer}
+.add-workout-btn{width:100%;padding:14px;background:none;border:2px dashed #DDDDD8;border-radius:var(--radius);color:var(--muted);font-size:14px;cursor:pointer;margin-top:4px;transition:all 0.2s}
+.add-workout-btn:hover{border-color:var(--accent);color:var(--accent)}
+
+/* ── LIBRARY ───────────────────────────────  */
+.lib-header{padding:52px 16px 16px;background:var(--header)}
+.lib-title{font-size:24px;font-weight:800;color:#FFF;margin-bottom:14px}
+.search-wrap{position:relative}
+.search-input{width:100%;padding:13px 16px 13px 44px;border-radius:var(--radius-sm);border:none;font-size:15px;background:#FFF;color:var(--text);outline:none}
+.search-icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:#AAA;font-size:16px}
+.filter-btn{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;color:var(--accent);font-size:13px;font-weight:700;display:flex;align-items:center;gap:3px}
+.filter-badge{background:var(--accent);color:#FFF;border-radius:10px;padding:1px 6px;font-size:10px;font-weight:700}
+.chips-row{display:flex;gap:8px;overflow-x:auto;padding:14px 16px 4px;scrollbar-width:none;background:var(--header)}
+.chips-row::-webkit-scrollbar{display:none}
+.chip{flex-shrink:0;padding:7px 14px;border-radius:20px;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;border:1.5px solid rgba(255,255,255,0.2);color:rgba(255,255,255,0.8);background:transparent;transition:all 0.2s}
+.chip.active{background:var(--accent);border-color:var(--accent);color:#FFF}
+.lib-body{padding:14px 16px}
+.ex-card{background:var(--card);border-radius:var(--radius-sm);padding:14px 16px;display:flex;align-items:center;gap:14px;margin-bottom:10px;border:1px solid var(--border);cursor:pointer;transition:transform 0.1s}
+.ex-card:active{transform:scale(0.99)}
+.ex-icon{width:44px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0}
+.ex-info{flex:1;min-width:0}
+.ex-name{font-size:15px;font-weight:700;color:var(--text);margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
+.ex-meta{font-size:12px;color:var(--muted)}
+.ex-equip{font-size:11px;padding:3px 8px;border-radius:20px;background:#F0F0EE;color:var(--muted);font-weight:600;flex-shrink:0}
+
+/* ── NUTRITION STUB ────────────────────────  */
+.nutr-header{padding:52px 22px 20px;background:var(--header)}
+.nutr-title{font-size:24px;font-weight:800;color:#FFF;margin-bottom:4px}
+.nutr-date{font-size:13px;color:rgba(255,255,255,0.5)}
+.meal-card{background:var(--card);border-radius:var(--radius);border:1px solid var(--border);margin-bottom:12px;overflow:hidden}
+.meal-header{padding:14px 16px;display:flex;justify-content:space-between;align-items:center}
+.meal-name{font-size:15px;font-weight:700;color:var(--text)}
+.meal-cal{font-size:13px;color:var(--muted)}
+.meal-add{padding:4px 12px;border:1.5px solid var(--accent);border-radius:8px;color:var(--accent);font-size:12px;font-weight:700;background:none;cursor:pointer}
+.meal-empty{padding:12px 16px;font-size:13px;color:var(--muted);border-top:1px solid var(--border)}
+.food-item{display:flex;align-items:center;gap:8px;padding:10px 16px;border-top:1px solid var(--border)}
+.food-item-name{font-size:14px;font-weight:600;color:var(--text)}
+.food-item-detail{font-size:11px;color:var(--muted);margin-top:1px}
+.food-item-macros{font-size:11px;color:var(--muted);white-space:nowrap;margin-left:auto}
+.food-item-del{background:none;border:none;color:var(--muted);font-size:16px;cursor:pointer;padding:0 0 0 8px;line-height:1;flex-shrink:0}
+.nutr-summary{background:var(--card);border-radius:var(--radius);border:1px solid var(--border);padding:16px;margin-bottom:16px}
+.nutr-cal-row{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:14px}
+.nutr-cal-num{font-size:28px;font-weight:800;color:var(--text)}
+.nutr-cal-goal{font-size:13px;color:var(--muted)}
+.food-search-item{padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer;display:flex;justify-content:space-between;align-items:center}
+.food-search-item:last-child{border-bottom:none}
+.food-search-item:active{opacity:0.7}
+.food-search-name{font-size:14px;font-weight:600;color:var(--text)}
+.food-search-meta{font-size:12px;color:var(--muted);margin-top:2px}
+.food-amount-section{background:var(--bg);border-radius:var(--radius-sm);padding:14px;margin:12px 0}
+.food-amount-preview{font-size:13px;color:var(--muted);margin-top:8px;line-height:1.6}
+
+/* ── PROFILE ───────────────────────────────  */
+.prof-header{padding:52px 22px 28px;background:var(--text);text-align:center}
+.prof-avatar{width:72px;height:72px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;margin:0 auto 14px;font-size:26px;font-weight:800;color:#FFF}
+.prof-name{font-size:22px;font-weight:800;color:#FFF;margin-bottom:4px}
+.prof-goal{font-size:13px;color:rgba(255,255,255,0.5)}
+.prof-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;padding:18px 16px}
+.ps-card{background:var(--card);border-radius:var(--radius-sm);padding:14px 12px;text-align:center;border:1px solid var(--border)}
+.ps-num{font-size:22px;font-weight:800;color:var(--text)}
+.ps-label{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-top:2px}
+.settings-section{padding:0 16px 12px}
+/* ── ACHIEVEMENT TOAST ───────────────────── */
+#achievementToast{position:absolute;top:60px;left:50%;transform:translateX(-50%) translateY(-20px);background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:16px 20px;text-align:center;box-shadow:0 8px 32px rgba(0,0,0,0.18);z-index:500;width:260px;opacity:0;pointer-events:none;transition:opacity 0.3s,transform 0.3s}
+#achievementToast.show{opacity:1;transform:translateX(-50%) translateY(0)}
+
+/* ── ACHIEVEMENT GRID ────────────────────── */
+.ach-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-bottom:20px}
+.ach-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-sm);padding:12px;display:flex;gap:10px;align-items:center}
+.ach-card.locked{opacity:0.38}
+.ach-icon{font-size:26px;flex-shrink:0}
+.ach-name{font-size:13px;font-weight:700;color:var(--text);line-height:1.2}
+.ach-desc{font-size:11px;color:var(--muted);margin-top:2px;line-height:1.3}
+
+.theme-row{display:flex;gap:10px;margin-bottom:16px}
+.theme-swatch{flex:1;height:52px;border-radius:var(--radius-sm);cursor:pointer;border:2px solid transparent;overflow:hidden;transition:border-color 0.2s,transform 0.15s;position:relative}
+.theme-swatch:active{transform:scale(0.95)}
+.theme-swatch.active{border-color:var(--accent)}
+.theme-swatch-top{height:60%;width:100%}
+.theme-swatch-bot{height:40%;width:100%}
+.theme-swatch-check{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,0.5);opacity:0}
+.theme-swatch.active .theme-swatch-check{opacity:1}
+.theme-label{text-align:center;font-size:10px;color:var(--muted);margin-top:4px;font-weight:500}
+.settings-item{display:flex;justify-content:space-between;align-items:center;padding:15px 16px;background:var(--card);margin-bottom:2px;cursor:pointer;border:1px solid var(--border)}
+.settings-item:first-child{border-radius:var(--radius) var(--radius) 0 0}
+.settings-item:last-child{border-radius:0 0 var(--radius) var(--radius)}
+.si-label{font-size:15px;color:var(--text)}
+.si-val{font-size:14px;color:var(--muted)}
+
+/* ── ACTIVE WORKOUT ──────────────────────── */
+#active-workout{position:absolute;inset:0;background:#0F0F0F;display:none;flex-direction:column;z-index:200}
+.aw-header{padding:52px 22px 20px;display:flex;justify-content:space-between;align-items:flex-start}
+.aw-name{font-size:22px;font-weight:800;color:#FFF}
+.aw-timer{font-size:14px;color:#888;margin-top:4px}
+.aw-close{background:rgba(255,255,255,0.1);border:none;color:#FFF;width:36px;height:36px;border-radius:50%;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center}
+.aw-body{flex:1;overflow-y:auto;padding:0 16px 16px}
+.aw-ex-card{background:#1A1A1A;border-radius:var(--radius);padding:16px;margin-bottom:12px}
+.aw-ex-name{font-size:17px;font-weight:700;color:#FFF;margin-bottom:12px}
+.aw-sets{display:flex;flex-direction:column;gap:8px}
+.aw-set-row{display:grid;grid-template-columns:28px 1fr 1fr auto;gap:8px;align-items:center}
+.set-num{font-size:12px;color:#666;font-weight:700;text-align:center}
+.set-input{padding:10px 12px;background:#2A2A2A;border:1px solid #333;border-radius:8px;color:#FFF;font-size:16px;text-align:center;width:100%;outline:none}
+.set-input:focus{border-color:var(--accent)}
+.set-done{width:34px;height:34px;border-radius:8px;border:1.5px solid #444;background:none;color:#666;font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center}
+.set-done.completed{background:var(--accent);border-color:var(--accent);color:#FFF}
+.aw-footer{padding:16px;border-top:1px solid #222}
+.btn-finish{width:100%;padding:16px;background:#FFF;color:#0F0F0F;border:none;border-radius:var(--radius);font-size:16px;font-weight:800;cursor:pointer}
+
+/* ── MODAL ────────────────────────────────  */
+.modal-overlay{position:absolute;inset:0;background:rgba(0,0,0,0.5);z-index:300;display:none;align-items:flex-end}
+.modal-overlay.show{display:flex}
+.modal-sheet{background:#FFF;border-radius:var(--radius) var(--radius) 0 0;width:100%;padding:24px 22px 40px;max-height:85vh;overflow-y:auto}
+.modal-handle{width:36px;height:4px;background:#DDD;border-radius:2px;margin:0 auto 20px}
+.modal-title{font-size:20px;font-weight:800;color:var(--text);margin-bottom:20px}
+
+/* ── FILTER MODAL ────────────────────────  */
+.filter-overlay{position:absolute;inset:0;background:rgba(0,0,0,0.5);z-index:400;display:none;align-items:flex-end}
+.filter-overlay.show{display:flex}
+.create-ex-overlay{position:absolute;inset:0;background:rgba(0,0,0,0.5);z-index:450;display:none;align-items:flex-end}
+.create-ex-overlay.show{display:flex}
+.create-ex-sheet{background:var(--card);border-radius:var(--radius) var(--radius) 0 0;width:100%;padding:24px 22px 40px;max-height:90vh;overflow-y:auto}
+.create-ex-sheet .field{margin-bottom:12px}
+.create-ex-sheet .field label{display:block;font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
+.create-ex-sheet .field input,.create-ex-sheet .field select{width:100%;padding:10px 12px;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:15px;color:var(--text);background:var(--bg);box-sizing:border-box}
+.ce-instruction-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}
+.ce-instruction-row input{flex:1;padding:10px 12px;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:14px;color:var(--text);background:var(--bg)}
+.ce-instruction-row button{width:32px;height:32px;background:#FEE2E2;border:none;border-radius:var(--radius-sm);color:#E53E3E;font-size:16px;cursor:pointer;flex-shrink:0}
+.lib-fab{position:sticky;bottom:16px;left:50%;transform:translateX(-50%);display:block;margin:16px auto 0;padding:13px 28px;background:var(--accent);color:#FFF;font-size:15px;font-weight:700;border:none;border-radius:999px;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,0.18);width:max-content}
+.ex-card-custom{border:1.5px solid var(--accent);}
+.filter-sheet{background:#FFF;border-radius:var(--radius) var(--radius) 0 0;width:100%;padding:24px 22px 40px;max-height:80vh;overflow-y:auto}
+.filter-section-title{font-size:11px;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;color:var(--muted);margin:18px 0 10px}
+.filter-section-title:first-child{margin-top:0}
+.filter-chip-row{display:flex;flex-wrap:wrap;gap:8px}
+.filter-chip{padding:8px 14px;border:1.5px solid #E8E8E8;border-radius:20px;font-size:13px;cursor:pointer;transition:all 0.2s;color:var(--text);background:#FFF}
+.filter-chip.active{border-color:var(--accent);background:var(--accent-light);color:var(--accent);font-weight:600}
+.filter-actions{display:flex;gap:10px;margin-top:24px}
+.filter-reset{flex:1;padding:14px;background:#F5F5F3;color:var(--text);font-size:15px;font-weight:600;border:none;border-radius:var(--radius);cursor:pointer}
+.filter-apply{flex:2;padding:14px;background:var(--accent);color:#FFF;font-size:15px;font-weight:700;border:none;border-radius:var(--radius);cursor:pointer}
+
+/* ── REST TIMER ───────────────────────────  */
+.rest-overlay{position:absolute;inset:0;background:rgba(0,0,0,0.85);z-index:250;display:none;flex-direction:column;align-items:center;justify-content:center}
+.rest-overlay.show{display:flex}
+.rest-num{font-size:80px;font-weight:800;color:#FFF;font-variant-numeric:tabular-nums}
+.rest-label{font-size:14px;color:#888;letter-spacing:0.1em;text-transform:uppercase;margin-bottom:32px}
+.rest-skip{padding:12px 32px;border:2px solid rgba(255,255,255,0.3);border-radius:12px;background:none;color:#FFF;font-size:14px;font-weight:700;cursor:pointer}
+</style>
+</head>
+<body>
+<div id="root">
+
+<div id="achievementToast"></div>
+
+<!-- SPLASH -->
+<div id="splash">
+  <div class="splash-ring">
+    <svg width="140" height="140" viewBox="0 0 140 140">
+      <circle cx="70" cy="70" r="60" fill="none" stroke="#1A1A1A" stroke-width="3"/>
+      <circle cx="70" cy="70" r="60" fill="none" stroke="#E85D26" stroke-width="3"
+        stroke-dasharray="377" stroke-dashoffset="188" stroke-linecap="round"/>
+    </svg>
+    <div class="splash-logo">
+      <div class="splash-name">FORTIS</div>
+      <div class="splash-sub">Träningsapp</div>
+    </div>
+  </div>
+  <div class="splash-progress"><div class="splash-fill" id="splashFill"></div></div>
+</div>
+
+<!-- ONBOARDING -->
+<div id="onboarding">
+  <div class="ob-header">
+    <div class="ob-steps" id="obSteps"></div>
+    <div class="ob-title" id="obTitle"></div>
+    <div class="ob-desc" id="obDesc"></div>
+  </div>
+  <div class="ob-body" id="obBody"></div>
+  <div class="ob-footer" id="obFooter"></div>
+</div>
+
+<!-- MAIN APP -->
+<div id="app">
+  <!-- Home -->
+  <div class="screen" id="tabHome">
+    <div class="home-header">
+      <div class="greeting-sub">God morgon</div>
+      <div class="greeting" id="homeGreeting">Jens</div>
+      <div class="streak-pill">🔥 <span id="streakCount">0</span> dagars streak</div>
+    </div>
+    <div class="home-content">
+      <div class="section-title">Kalorier idag</div>
+      <div class="card calorie-card">
+        <div class="ring-wrap">
+          <svg width="100" height="100" viewBox="0 0 100 100">
+            <circle cx="50" cy="50" r="42" fill="none" stroke="#F0F0EE" stroke-width="8"/>
+            <circle id="calRing" cx="50" cy="50" r="42" fill="none" stroke="#E85D26" stroke-width="8"
+              stroke-dasharray="264" stroke-dashoffset="264" stroke-linecap="round"
+              style="transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset 0.8s ease"/>
+          </svg>
+          <div class="ring-center">
+            <div class="ring-num" id="calsLeft">—</div>
+            <div class="ring-label">kvar</div>
+          </div>
+        </div>
+        <div class="ring-macros">
+          <div class="rm-row">
+            <div class="rm-label"><span class="rm-name">Protein</span><span class="rm-val" id="mProtein">0<span class="rm-unit">g</span></span></div>
+            <div class="rm-bar"><div class="rm-fill" id="mProteinBar" style="background:#E85D26;width:0%"></div></div>
+          </div>
+          <div class="rm-row">
+            <div class="rm-label"><span class="rm-name">Kolhydrater</span><span class="rm-val" id="mCarbs">0<span class="rm-unit">g</span></span></div>
+            <div class="rm-bar"><div class="rm-fill" id="mCarbsBar" style="background:#2A6AE8;width:0%"></div></div>
+          </div>
+          <div class="rm-row">
+            <div class="rm-label"><span class="rm-name">Fett</span><span class="rm-val" id="mFat">0<span class="rm-unit">g</span></span></div>
+            <div class="rm-bar"><div class="rm-fill" id="mFatBar" style="background:#22A647;width:0%"></div></div>
+          </div>
+        </div>
+      </div>
+
+      <div class="section-title">Vatten</div>
+      <div class="card">
+        <div class="water-row">
+          <div class="water-drops" id="waterDrops"></div>
+          <button class="water-btn" onclick="addWater()">+2,5 dl</button>
+        </div>
+        <div style="font-size:12px;color:var(--muted);margin-top:10px" id="waterLabel">0 / 2500 ml</div>
+      </div>
+
+      <div class="section-title">Dagens pass</div>
+      <div class="card" id="todayWorkoutCard"></div>
+    </div>
+  </div>
+
+  <!-- Schedule -->
+  <div class="screen" id="tabSchedule" style="display:none">
+    <div class="sched-header">
+      <div class="sched-title">Schema</div>
+      <div class="week-strip" id="weekStrip"></div>
+    </div>
+    <div class="sched-body" id="schedBody"></div>
+  </div>
+
+  <!-- Library -->
+  <div class="screen" id="tabLibrary" style="display:none">
+    <div class="lib-header">
+      <div class="lib-title">Övningsbibliotek</div>
+      <div class="search-wrap">
+        <span class="search-icon">🔍</span>
+        <input class="search-input" type="text" placeholder="Sök övning..." id="libSearch" oninput="filterExercises()">
+        <button class="filter-btn" onclick="toggleFilterModal()">Filter <span class="filter-badge" id="filterBadge" style="display:none">0</span></button>
+      </div>
+    </div>
+    <div class="chips-row" id="equipChips"></div>
+    <div class="lib-body" id="libBody"></div>
+    <button class="lib-fab" onclick="openCreateExercise()">+ Ny övning</button>
+  </div>
+
+  <!-- Nutrition -->
+  <div class="screen" id="tabNutrition" style="display:none">
+    <div class="nutr-header">
+      <div class="nutr-title">Kost</div>
+      <div class="nutr-date" id="nutrDate"></div>
+    </div>
+    <div style="padding:18px 16px">
+      <div class="nutr-summary" id="nutrSummary"></div>
+      <div class="section-title" style="margin-bottom:10px">Måltider</div>
+      <div id="mealCards"></div>
+      <span id="nutrProtGoal" style="display:none"></span>
+      <span id="nutrCarbGoal" style="display:none"></span>
+      <span id="nutrFatGoal" style="display:none"></span>
+    </div>
+  </div>
+
+  <!-- Profile -->
+  <div class="screen" id="tabProfile" style="display:none">
+    <div class="prof-header">
+      <div class="prof-avatar" id="profAvatar">J</div>
+      <div class="prof-name" id="profName">—</div>
+      <div class="prof-goal" id="profGoalText">—</div>
+    </div>
+    <div class="prof-stats">
+      <div class="ps-card"><div class="ps-num" id="psTotal">0</div><div class="ps-label">Pass totalt</div></div>
+      <div class="ps-card"><div class="ps-num" id="psStreak">0</div><div class="ps-label">Streak</div></div>
+      <div class="ps-card"><div class="ps-num" id="psWeight">—</div><div class="ps-label">Kg</div></div>
+    </div>
+    <div class="settings-section">
+      <div class="section-title" style="padding:0 0 10px">Achievements</div>
+      <div class="ach-grid" id="achGrid"></div>
+      <div class="section-title" style="padding:0 0 10px">Inställningar</div>
+      <div id="settingsItems"></div>
+    </div>
+    <div style="padding:0 16px 20px">
+      <button onclick="resetApp()" style="width:100%;padding:14px;border:1.5px solid #E0E0E0;border-radius:var(--radius);background:none;color:#CC3333;font-size:14px;font-weight:600;cursor:pointer">Återställ app</button>
+    </div>
+  </div>
+
+  <nav class="bottom-nav">
+    <button class="nav-item active" onclick="switchTab('Home')" id="navHome">
+      <span class="nav-icon">🏠</span><span class="nav-label">Hem</span>
+    </button>
+    <button class="nav-item" onclick="switchTab('Schedule')" id="navSchedule">
+      <span class="nav-icon">📅</span><span class="nav-label">Schema</span>
+    </button>
+    <button class="nav-item" onclick="switchTab('Library')" id="navLibrary">
+      <span class="nav-icon">📚</span><span class="nav-label">Bibliotek</span>
+    </button>
+    <button class="nav-item" onclick="switchTab('Nutrition')" id="navNutrition">
+      <span class="nav-icon">🍎</span><span class="nav-label">Kost</span>
+    </button>
+    <button class="nav-item" onclick="switchTab('Profile')" id="navProfile">
+      <span class="nav-icon">👤</span><span class="nav-label">Profil</span>
+    </button>
+  </nav>
+</div>
+
+<!-- Active Workout View -->
+<div id="active-workout">
+  <div class="aw-header">
+    <div>
+      <div class="aw-name" id="awName">Pass</div>
+      <div class="aw-timer" id="awTimer">00:00</div>
+    </div>
+    <button class="aw-close" onclick="closeWorkout()">✕</button>
+  </div>
+  <div class="aw-body" id="awBody"></div>
+  <div class="aw-footer">
+    <button class="btn-finish" onclick="finishWorkout()">Avsluta pass</button>
+  </div>
+</div>
+
+<!-- Rest Timer Overlay -->
+<div class="rest-overlay" id="restOverlay">
+  <div class="rest-label">Vila</div>
+  <div class="rest-num" id="restNum">60</div>
+  <button class="rest-skip" onclick="skipRest()">Hoppa över</button>
+</div>
+
+<!-- Modal (Exercise detail / Add workout) -->
+<div class="modal-overlay" id="modalOverlay" onclick="closeModal(event)">
+  <div class="modal-sheet" id="modalSheet">
+    <div class="modal-handle"></div>
+    <div class="modal-title" id="modalTitle"></div>
+    <div id="modalBody"></div>
+  </div>
+</div>
+
+<div class="filter-overlay" id="filterOverlay" onclick="closeFilterOverlay(event)">
+  <div class="filter-sheet">
+    <div class="modal-handle"></div>
+    <div class="modal-title">Filter</div>
+    <div class="filter-section-title">Muskelgrupp</div>
+    <div class="filter-chip-row" id="fmMuscles"></div>
+    <div class="filter-section-title">Svårighet</div>
+    <div class="filter-chip-row" id="fmDiffs"></div>
+    <div class="filter-actions">
+      <button class="filter-reset" onclick="resetFilters()">Återställ</button>
+      <button class="filter-apply" onclick="applyFilters()">Visa resultat</button>
+    </div>
+  </div>
+</div>
+
+<div class="create-ex-overlay" id="createExOverlay" onclick="closeCreateExercise(event)">
+  <div class="create-ex-sheet">
+    <div class="modal-handle"></div>
+    <div class="modal-title">Skapa övning</div>
+    <div class="field"><label>Namn</label><input type="text" id="ceName" placeholder="Övningens namn"></div>
+    <div class="field"><label>Ikon (emoji)</label><input type="text" id="ceIcon" placeholder="💪" maxlength="2" style="width:64px"></div>
+    <div class="field"><label>Muskelgrupp</label>
+      <select id="ceMuscle">
+        <option>Bröst</option><option>Rygg</option><option>Ben</option><option>Axlar</option>
+        <option>Armar</option><option>Core</option><option>Helkropp</option><option>Kondition</option>
+      </select>
+    </div>
+    <div class="field"><label>Sekundära muskler</label><input type="text" id="ceSecondary" placeholder="t.ex. Triceps, Axlar"></div>
+    <div class="field"><label>Utrustning</label>
+      <select id="ceEquip">
+        <option>Kroppsvikt</option><option>Hantel</option><option>Kettlebell</option><option>Skivstång</option>
+        <option>Kabelmaskin</option><option>Maskin</option><option>Motståndsband</option><option>Löpband</option>
+      </select>
+    </div>
+    <div class="field"><label>Svårighet</label>
+      <select id="ceDiff"><option>Nybörjare</option><option>Medel</option><option>Avancerad</option></select>
+    </div>
+    <div class="field"><label>Typ</label>
+      <select id="ceType"><option>Styrka</option><option>Kondition</option><option>Rörlighet</option></select>
+    </div>
+    <div class="filter-section-title" style="margin-top:16px">Instruktioner</div>
+    <div id="ceInstructions"></div>
+    <button class="btn-ghost" style="margin-top:8px;font-size:14px" onclick="addInstruction()">+ Lägg till steg</button>
+    <div style="display:flex;gap:10px;margin-top:20px">
+      <button class="filter-reset" onclick="closeCreateExercise()">Avbryt</button>
+      <button class="filter-apply" onclick="saveCustomExercise()">Spara övning</button>
+    </div>
+  </div>
+</div>
+
+<script>
+// ── DATA ─────────────────────────────────────────────────
+const EXERCISES=[
+  // ── BRÖST ──────────────────────────────────────────────
+  {id:'pushup',name:'Armhävningar',muscle:'Bröst',secondary:'Triceps, Axlar',equip:'Kroppsvikt',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Lägg händerna axelbrett isär på golvet','Håll kroppen rak från huvud till häl','Sänk bröstet mot golvet','Pressa upp till startläget']},
+  {id:'bench_press',name:'Bänkpress',muscle:'Bröst',secondary:'Triceps, Axlar',equip:'Skivstång',icon:'🏋️',diff:'Medel',type:'Styrka',instructions:['Ligg på bänken med fötterna i golvet','Grip stången lite bredare än axelbredd','Sänk stången till bröstet','Pressa upp explosivt']},
+  {id:'incline_bench_press',name:'Incline Bench Press',muscle:'Bröst',secondary:'Triceps, Axlar',equip:'Skivstång',icon:'🏋️',diff:'Medel',type:'Styrka',instructions:['Ställ bänken på 30–45°','Grip stången axelbrett','Sänk stången mot övre bröstet','Pressa upp och in']},
+  {id:'db_bench_press',name:'Dumbbell Bench Press',muscle:'Bröst',secondary:'Triceps, Axlar',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på bänk med en hantel i varje hand','Hantelerna vid sidan av bröstet','Pressa rakt upp','Sänk kontrollerat']},
+  {id:'db_incline_press',name:'Dumbbell Incline Press',muscle:'Bröst',secondary:'Axlar, Triceps',equip:'Hantel',icon:'💪',diff:'Medel',type:'Styrka',instructions:['Bänk på 30–45°, hantel i varje hand','Hantelerna vid övre bröstet','Pressa upp','Sänk kontrollerat till startläge']},
+  {id:'db_floor_press',name:'Dumbbell Floor Press',muscle:'Bröst',secondary:'Triceps, Axlar',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på golvet med knäna böjda','Hantel i varje hand vid sidan av bröstet','Pressa rakt upp','Sänk tills armbågarna nuddar golvet']},
+  {id:'db_incline_fly',name:'Dumbbell Incline Fly',muscle:'Bröst',secondary:'Axlar',equip:'Hantel',icon:'🦅',diff:'Medel',type:'Styrka',instructions:['Bänk på 30–45°, hantel i varje hand','Armarna nästan raka, lätt böjda i armbågen','Sänk hantelerna i en vid båge','Pressa ihop framför bröstet']},
+  {id:'cable_fly',name:'Cable Fly',muscle:'Bröst',secondary:'Axlar',equip:'Kabelmaskin',icon:'🔗',diff:'Nybörjare',type:'Styrka',instructions:['Ställ kabler i brösthöjd','Stå i mitten, ett steg framåt','Dra handtagen framåt och ihop','Kontrollera tillbaka']},
+  {id:'push_up_diamond',name:'Diamond Push-Up',muscle:'Bröst',secondary:'Triceps',equip:'Kroppsvikt',icon:'💎',diff:'Medel',type:'Styrka',instructions:['Händerna tätt ihop, tummar och pekfingrar bildar en romb','Kroppen rak','Sänk bröstet mot händerna','Pressa upp']},
+  {id:'machine_chest_press',name:'Machine Chest Press',muscle:'Bröst',secondary:'Triceps, Axlar',equip:'Maskin',icon:'🔩',diff:'Nybörjare',type:'Styrka',instructions:['Justera sätet, händtagen vid bröstnivå','Grip handtagen, fötterna i golvet','Pressa rakt framåt','Kontrollera tillbaka']},
+
+  // ── RYGG ───────────────────────────────────────────────
+  {id:'pullup',name:'Chins (underhand)',muscle:'Rygg',secondary:'Biceps',equip:'Kroppsvikt',icon:'🏋️',diff:'Medel',type:'Styrka',instructions:['Grip stången underhands, axelbrett','Häng med raka armar','Dra dig upp tills hakan är över stången','Sänk kontrollerat']},
+  {id:'pull_up',name:'Pull-Up (overhand)',muscle:'Rygg',secondary:'Biceps, Axlar',equip:'Kroppsvikt',icon:'🏋️',diff:'Medel',type:'Styrka',instructions:['Grip stången överhands, lite bredare än axelbredd','Häng med raka armar','Dra dig upp tills bröstet nuddar stången','Sänk kontrollerat']},
+  {id:'inverted_row',name:'Inverted Row',muscle:'Rygg',secondary:'Biceps, Core',equip:'Kroppsvikt',icon:'🔄',diff:'Nybörjare',type:'Styrka',instructions:['Ligg under en stång i höfthöjd','Grip stången, kroppen rak','Dra bröstet upp mot stången','Sänk kontrollerat']},
+  {id:'deadlift',name:'Marklyft',muscle:'Rygg',secondary:'Ben, Rumpa',equip:'Skivstång',icon:'🏋️',diff:'Avancerad',type:'Styrka',instructions:['Stå med stången över fotmitt','Böj i höft och knä, rygg rak','Grip stången axelbrett','Pressa marken ifrån dig, höfterna framåt']},
+  {id:'lat_pulldown',name:'Latsdrag',muscle:'Rygg',secondary:'Biceps',equip:'Kabelmaskin',icon:'🔗',diff:'Nybörjare',type:'Styrka',instructions:['Sitt vid maskinen och greppa stången brett','Dra ner stången till övre bröstet','Håll armbågarna nere och bakåt','Kontrollera uppgången']},
+  {id:'cable_row',name:'Kabeldrag sittande',muscle:'Rygg',secondary:'Biceps, Axlar',equip:'Kabelmaskin',icon:'🔗',diff:'Nybörjare',type:'Styrka',instructions:['Sitt med fötterna mot plattformen','Håll ryggen rak','Dra handtaget mot magen','Pressa ihop skulderbladen']},
+  {id:'db_bent_row',name:'Dumbbell Bent Over Row',muscle:'Rygg',secondary:'Biceps, Axlar',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Böj dig framåt i höften, ryggen rak','Hantel i varje hand, armarna hängande','Dra hantelerna mot höfterna','Pressa skulderbladen ihop']},
+  {id:'barbell_row',name:'Barbell Bent Over Row',muscle:'Rygg',secondary:'Biceps, Axlar',equip:'Skivstång',icon:'🏋️',diff:'Medel',type:'Styrka',instructions:['Böj dig 45° framåt, ryggen rak','Grip stången axelbrett underhands','Dra stången mot naveln','Sänk kontrollerat']},
+  {id:'db_pullover',name:'Dumbbell Pullover',muscle:'Rygg',secondary:'Bröst, Triceps',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Ligg tvärs över bänk, överkropp plant','Håll en hantel med båda händer ovan bröstet','Sänk hanteln bakom huvudet i en båge','Dra tillbaka upp']},
+  {id:'superman',name:'Superman',muscle:'Rygg',secondary:'Rumpa',equip:'Kroppsvikt',icon:'🦸',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på mage, armar sträckta framåt','Lyft armar och ben från golvet simultant','Håll 2–3 sek i toppläget','Sänk kontrollerat']},
+  {id:'seated_row_machine',name:'Seated Row Machine',muscle:'Rygg',secondary:'Biceps, Axlar',equip:'Maskin',icon:'🔩',diff:'Nybörjare',type:'Styrka',instructions:['Sitt i maskinen, bröst mot stödplattan','Grip handtagen','Dra handtagen mot kroppen','Kontrollera tillbaka']},
+
+  // ── BEN ────────────────────────────────────────────────
+  {id:'squat',name:'Knäböj (kroppsvikt)',muscle:'Ben',secondary:'Rumpa, Core',equip:'Kroppsvikt',icon:'🦵',diff:'Nybörjare',type:'Styrka',instructions:['Stå axelbrett med fötterna','Sänk höfterna bakåt och nedåt','Knäna följer tårnas riktning','Pressa upp genom hälarna']},
+  {id:'barbell_squat',name:'Barbell Squat',muscle:'Ben',secondary:'Rumpa, Core',equip:'Skivstång',icon:'🏋️',diff:'Medel',type:'Styrka',instructions:['Stång på övre ryggen, axelbrett fötter','Bröst upprätt, ryggen neutral','Sänk höfterna nedåt och bakåt','Pressa upp explosivt']},
+  {id:'goblet_squat',name:'Goblet Squat',muscle:'Ben',secondary:'Core, Rumpa',equip:'Kettlebell',icon:'🫙',diff:'Nybörjare',type:'Styrka',instructions:['Håll kettlebell mot bröstet','Fötterna bredare än axelbrett','Böj knäna och sänk dig djupt','Pressa upp med bröst upprätt']},
+  {id:'lunges',name:'Utfall',muscle:'Ben',secondary:'Rumpa, Core',equip:'Kroppsvikt',icon:'🦵',diff:'Nybörjare',type:'Styrka',instructions:['Stå med fötterna ihop','Ta ett stort steg framåt','Böj båda knäna till 90°','Pressa upp och byt ben']},
+  {id:'bulgarian_split_squat',name:'Bulgarian Split Squat',muscle:'Ben',secondary:'Rumpa, Core',equip:'Kroppsvikt',icon:'🦵',diff:'Medel',type:'Styrka',instructions:['Bakre foten på en bänk','Fram-foten ett stort steg framåt','Sänk bakre knäet mot golvet','Pressa upp via framfoten']},
+  {id:'leg_press',name:'Benpress',muscle:'Ben',secondary:'Rumpa',equip:'Maskin',icon:'🦵',diff:'Nybörjare',type:'Styrka',instructions:['Sitt i maskinen med fötterna axelbrett','Böj knäna till 90°','Pressa plattan ifrån dig','Sträck inte ut knäna helt']},
+  {id:'leg_extension',name:'Leg Extension',muscle:'Ben',secondary:'',equip:'Maskin',icon:'🦵',diff:'Nybörjare',type:'Styrka',instructions:['Sitt i maskinen, underben mot kudden','Håll ryggen mot ryggstödet','Sträck ut benen till horisontellt','Sänk kontrollerat']},
+  {id:'leg_curl',name:'Leg Curl',muscle:'Ben',secondary:'',equip:'Maskin',icon:'🦵',diff:'Nybörjare',type:'Styrka',instructions:['Ligg i maskinen (eller sitt), vaden mot kudden','Böj knäna och dra hälarna mot rumpan','Håll i toppläget en sekund','Sänk kontrollerat']},
+  {id:'kb_swing',name:'Kettlebell Swing',muscle:'Ben',secondary:'Rygg, Rumpa',equip:'Kettlebell',icon:'⚡',diff:'Medel',type:'Styrka',instructions:['Stå axelbrett, kettlebell mellan benen','Böj i höften, svinga bakåt','Explosiv höftrörelse framåt, svinga upp till brösthöjd','Kontrollera pendeln tillbaka']},
+  {id:'kb_sumo_deadlift',name:'Kettlebell Sumo Deadlift',muscle:'Ben',secondary:'Rygg, Rumpa',equip:'Kettlebell',icon:'🫙',diff:'Nybörjare',type:'Styrka',instructions:['Brett fotläge, tår utåt','Kettlebell mellan fötterna','Höft och knä böjt, rygg rak','Pressa upp, sträck höft och knä simultant']},
+  {id:'db_front_squat',name:'Dumbbell Front Squat',muscle:'Ben',secondary:'Core, Rumpa',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Håll hantel i varje hand på axlarna','Fötterna axelbrett','Sänk rakt ner, bröst upprätt','Pressa upp']},
+  {id:'db_hip_thrust',name:'Dumbbell Hip Thrust',muscle:'Ben',secondary:'Core',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Övre rygg mot bänk, fötter i golvet','Hantel på höfterna','Sänk rumpan mot golvet','Pressa höfterna rakt upp, kläm rumpan']},
+  {id:'db_rdl',name:'Romanian Deadlift (DB)',muscle:'Ben',secondary:'Rygg, Rumpa',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Stå med hantel i varje hand framför låren','Böj i höften, hantelerna glider längs benen','Känn sträcket i baklåren','Pressa höfterna framåt till startläget']},
+  {id:'calf_raise',name:'Standing Calf Raise',muscle:'Ben',secondary:'',equip:'Kroppsvikt',icon:'🦶',diff:'Nybörjare',type:'Styrka',instructions:['Stå på kanten av ett steg','Sänk hälarna under stegnivå','Pressa upp på tårna','Håll i toppläget en sekund']},
+  {id:'step_ups',name:'Step-Ups',muscle:'Ben',secondary:'Rumpa, Core',equip:'Kroppsvikt',icon:'🦵',diff:'Nybörjare',type:'Styrka',instructions:['Stå framför en stabil yta (bänk/steg)','Kliv upp med ett ben','Ta med dig det andra benet','Kliv ner kontrollerat och byt']},
+  {id:'box_squat',name:'Box Squat',muscle:'Ben',secondary:'Rumpa, Core',equip:'Kroppsvikt',icon:'📦',diff:'Nybörjare',type:'Styrka',instructions:['Stå framför en låg bänk eller box','Axelbrett fotläge','Sänk dig tills du nuddar boxen','Pressa upp utan att gunga']},
+  {id:'pistol_squat',name:'Pistol Squat',muscle:'Ben',secondary:'Core, Rumpa',equip:'Kroppsvikt',icon:'🦵',diff:'Avancerad',type:'Styrka',instructions:['Stå på ett ben, det andra rakt framåt','Armarna ut för balans','Sänk på ett ben så djupt du kan','Pressa upp']},
+  {id:'glute_bridge',name:'Glute Bridge',muscle:'Ben',secondary:'Core',equip:'Kroppsvikt',icon:'🌉',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på rygg, knäna böjda, fötter i golvet','Pressa höfterna rakt upp','Kläm rumpan hårt i toppläget','Sänk kontrollerat']},
+
+  // ── AXLAR ──────────────────────────────────────────────
+  {id:'shoulder_press',name:'Dumbbell Shoulder Press',muscle:'Axlar',secondary:'Triceps',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Sitt eller stå med hantel i varje hand','Hantelerna vid öronen','Pressa rakt upp','Sänk kontrollerat till öronnivå']},
+  {id:'overhead_press',name:'Overhead Press (Barbell)',muscle:'Axlar',secondary:'Triceps, Core',equip:'Skivstång',icon:'🏋️',diff:'Medel',type:'Styrka',instructions:['Stå med stången vid brösthöjd','Grip axelbrett','Pressa rakt upp tills armarna är raka','Sänk kontrollerat till startläge']},
+  {id:'lateral_raise',name:'Lateral Raise',muscle:'Axlar',secondary:'',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Stå med hantel i varje hand längs sidan','Lätt böjda armar','Lyft hantelerna till sidan upp till axelhöjd','Sänk kontrollerat']},
+  {id:'front_raise',name:'Front Raise',muscle:'Axlar',secondary:'',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Stå med hantel i varje hand','Lyft en hantel i taget rakt framåt till axelhöjd','Håll armbågen lätt böjd','Sänk kontrollerat och byt arm']},
+  {id:'rear_delt_fly',name:'Rear Delt Fly',muscle:'Axlar',secondary:'Rygg',equip:'Hantel',icon:'🦅',diff:'Nybörjare',type:'Styrka',instructions:['Böj dig 90° framåt, rygg rak','Hantel i varje hand hängande','Lyft hantelerna ut till sidan','Kläm skulderbladen ihop i toppen']},
+  {id:'face_pull',name:'Face Pull',muscle:'Axlar',secondary:'Rygg',equip:'Kabelmaskin',icon:'🔗',diff:'Nybörjare',type:'Styrka',instructions:['Ställ kabeln i ögonhöjd','Dra mot ansiktet med armbågarna högt','Pressa skulderbladen ihop','Kontrollera tillbaka']},
+  {id:'band_pull_apart',name:'Band Pull-Apart',muscle:'Axlar',secondary:'Rygg',equip:'Motståndsband',icon:'🔴',diff:'Nybörjare',type:'Styrka',instructions:['Håll bandet med båda händer framför bröstet, axelbrett','Sträck ut armarna','Dra bandet isär tills det nuddar bröstet','Kontrollera tillbaka']},
+  {id:'handstand_pushup',name:'Handstand Push-Up',muscle:'Axlar',secondary:'Triceps, Core',equip:'Kroppsvikt',icon:'🤸',diff:'Avancerad',type:'Styrka',instructions:['Stå på händer mot en vägg','Armarna raka, lägg händerna axelbrett','Böj armbågarna, sänk huvudet mot golvet','Pressa upp till startläge']},
+
+  // ── ARMAR ──────────────────────────────────────────────
+  {id:'dumbbell_curl',name:'Dumbbell Bicep Curl',muscle:'Armar',secondary:'Underarmar',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Stå med en hantel i varje hand','Armarna längs sidan','Curl upp mot axeln','Sänk kontrollerat']},
+  {id:'hammer_curl',name:'Hammer Curl',muscle:'Armar',secondary:'Underarmar',equip:'Hantel',icon:'🔨',diff:'Nybörjare',type:'Styrka',instructions:['Hantel i varje hand, neutralt grepp (tummen upp)','Håll armbågarna stilla längs sidan','Curl upp till axeln','Sänk kontrollerat']},
+  {id:'barbell_curl',name:'Barbell Curl',muscle:'Armar',secondary:'Underarmar',equip:'Skivstång',icon:'🏋️',diff:'Nybörjare',type:'Styrka',instructions:['Grip stången underhands, axelbrett','Armbågarna stilla vid sidan','Curl upp till axlarna','Sänk kontrollerat']},
+  {id:'zottman_curl',name:'Zottman Curl',muscle:'Armar',secondary:'Underarmar',equip:'Hantel',icon:'🔄',diff:'Medel',type:'Styrka',instructions:['Curl upp med underhands grepp','Rotera handleden i toppen (tummen nedåt)','Sänk med överhands grepp','Rotera tillbaka i botten']},
+  {id:'tricep_dips',name:'Dips',muscle:'Armar',secondary:'Bröst, Axlar',equip:'Kroppsvikt',icon:'💪',diff:'Medel',type:'Styrka',instructions:['Grip parallella stänger','Sänk kroppen ned tills armbågarna är 90°','Pressa upp','Luta dig inte för mycket framåt']},
+  {id:'cable_tricep_pushdown',name:'Cable Tricep Pushdown',muscle:'Armar',secondary:'',equip:'Kabelmaskin',icon:'🔗',diff:'Nybörjare',type:'Styrka',instructions:['Stå vid kabelmaskin, handtaget i brösthöjd','Armbågarna tätt mot sidan','Tryck handtaget rakt ner tills armarna är raka','Kontrollera tillbaka']},
+  {id:'db_tricep_kickback',name:'Dumbbell Tricep Kickback',muscle:'Armar',secondary:'',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Böj framåt, armbågen i 90°','Sträck ut armen bakåt tills den är rak','Håll armbågen stilla','Böj tillbaka kontrollerat']},
+  {id:'skull_crusher',name:'Skull Crusher',muscle:'Armar',secondary:'',equip:'Hantel',icon:'💀',diff:'Medel',type:'Styrka',instructions:['Ligg på bänk, hantel i varje hand ovan bröstet','Armbågarna pekande uppåt','Böj armbågarna, sänk hantelerna mot tinningarna','Pressa upp']},
+  {id:'overhead_tricep_ext',name:'Overhead Tricep Extension',muscle:'Armar',secondary:'',equip:'Hantel',icon:'💪',diff:'Nybörjare',type:'Styrka',instructions:['Stå eller sitt, håll en hantel med båda händer ovanför huvudet','Armbågarna tätt vid öronen','Böj armbågarna, sänk hanteln bakom huvudet','Pressa upp']},
+
+  // ── CORE ───────────────────────────────────────────────
+  {id:'plank',name:'Plank',muscle:'Core',secondary:'Axlar, Rygg',equip:'Kroppsvikt',icon:'🧘',diff:'Nybörjare',type:'Styrka',isTimer:true,instructions:['Lägg dig i push-up-position','Vila på underarmarna','Håll kroppen helt rak','Andas kontrollerat']},
+  {id:'situp',name:'Situps',muscle:'Core',secondary:'Höftböjare',equip:'Kroppsvikt',icon:'🧘',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på rygg med knäna böjda','Händerna bakom huvudet','Lyft överkroppen mot knäna','Sänk kontrollerat']},
+  {id:'crunches',name:'Crunches',muscle:'Core',secondary:'',equip:'Kroppsvikt',icon:'🧘',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på rygg, knäna böjda','Händerna vid tinningarna','Curl övre ryggen upp mot knäna','Sänk kontrollerat']},
+  {id:'russian_twist',name:'Russian Twist',muscle:'Core',secondary:'Obliques',equip:'Kroppsvikt',icon:'🌀',diff:'Nybörjare',type:'Styrka',instructions:['Sitt med knäna böjda och fötterna lätt lyfta','Luta dig lite bakåt','Rotera överkroppen sida till sida','Håll core spänt']},
+  {id:'knee_raise',name:'Hanging Knee Raise',muscle:'Core',secondary:'Höftböjare',equip:'Kroppsvikt',icon:'🧘',diff:'Medel',type:'Styrka',instructions:['Häng i en pull-up stång','Håll kroppen stilla','Lyft knäna mot bröstet','Sänk kontrollerat utan att gunga']},
+  {id:'leg_raise_lying',name:'Lying Leg Raise',muscle:'Core',secondary:'Höftböjare',equip:'Kroppsvikt',icon:'🧘',diff:'Medel',type:'Styrka',instructions:['Ligg på rygg, händerna under rumpan','Benen raka, lätt böjda','Lyft benen till 90°','Sänk utan att nudda golvet']},
+  {id:'plank_shoulder_tap',name:'Plank Shoulder Tap',muscle:'Core',secondary:'Axlar, Rumpa',equip:'Kroppsvikt',icon:'🧘',diff:'Medel',type:'Styrka',instructions:['Push-up position, händer under axlarna','Håll höfterna stilla','Lyft höger hand, nudda vänster axel','Byt sida, håll balansen']},
+  {id:'bicycle_crunch',name:'Bicycle Crunch',muscle:'Core',secondary:'Obliques',equip:'Kroppsvikt',icon:'🚴',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på rygg, händerna vid öronen','Lyft axlarna från golvet','Dra ena knäet mot bröstet, rotera mot det','Byt sida i ett cyklande rörelsemönster']},
+  {id:'dead_bug',name:'Dead Bug',muscle:'Core',secondary:'',equip:'Kroppsvikt',icon:'🐛',diff:'Nybörjare',type:'Styrka',instructions:['Ligg på rygg, armar raka upp, knäna böjda 90°','Håll ryggen tryckt mot golvet','Sänk höger arm och vänster ben simultant','Dra tillbaka och byt sida']},
+  {id:'plank_jacks',name:'Plank Jacks',muscle:'Core',secondary:'Ben, Axlar',equip:'Kroppsvikt',icon:'⚡',diff:'Medel',type:'Kondition',isTimer:true,instructions:['Push-up position','Hoppa fötterna isär och ihop (som jumping jacks)','Håll höfterna nere','Håll ett jämnt tempo']},
+  {id:'ab_wheel',name:'Ab Wheel Rollout',muscle:'Core',secondary:'Axlar, Rygg',equip:'Kroppsvikt',icon:'🌀',diff:'Avancerad',type:'Styrka',instructions:['Knäna i golvet, håll ab-hjulet','Rulla ut långsamt tills kroppen är nästan parallell med golvet','Håll core hårt spänt','Dra tillbaka med magen']},
+
+  // ── KONDITION ──────────────────────────────────────────
+  {id:'burpee',name:'Burpees',muscle:'Helkropp',secondary:'Core, Ben, Bröst',equip:'Kroppsvikt',icon:'⚡',diff:'Medel',type:'Kondition',instructions:['Stå rakt','Hoppa ner i push-up-position','Gör en armhävning','Hoppa upp med händerna ovan huvud']},
+  {id:'jumping_jacks',name:'Jumping Jacks',muscle:'Kondition',secondary:'Ben, Axlar',equip:'Kroppsvikt',icon:'⭐',diff:'Nybörjare',type:'Kondition',isTimer:true,instructions:['Stå med fötterna ihop, armar längs sidan','Hoppa ut fötterna och lyft armarna till sidan','Klappa händerna ovan huvud','Hoppa tillbaka till startläget']},
+  {id:'high_knees',name:'High Knees',muscle:'Kondition',secondary:'Core, Ben',equip:'Kroppsvikt',icon:'🏃',diff:'Nybörjare',type:'Kondition',isTimer:true,instructions:['Stå rakt','Spring på stället med höga knän','Knäna upp till höfthöjd','Håll ett snabbt tempo']},
+  {id:'mountain_climbers',name:'Mountain Climbers',muscle:'Kondition',secondary:'Core, Ben',equip:'Kroppsvikt',icon:'🧗',diff:'Nybörjare',type:'Kondition',isTimer:true,instructions:['Push-up position','Dra ett knä snabbt mot bröstet','Byt ben explosivt','Håll höfterna nere och jämn takt']},
+  {id:'jump_squat',name:'Jump Squat',muscle:'Kondition',secondary:'Ben, Rumpa',equip:'Kroppsvikt',icon:'⚡',diff:'Medel',type:'Kondition',instructions:['Axelbrett fotläge','Sänk ner i knäböj','Hoppa explosivt upp','Landa mjukt och gå direkt ner i nästa rep']},
+  {id:'box_jump',name:'Box Jump',muscle:'Kondition',secondary:'Ben, Rumpa',equip:'Kroppsvikt',icon:'📦',diff:'Medel',type:'Kondition',instructions:['Stå framför en box eller bänk','Böj knäna lätt','Hoppa explosivt upp på boxen','Kliv ner kontrollerat']},
+  {id:'treadmill',name:'Treadmill',muscle:'Kondition',secondary:'Ben',equip:'Löpband',icon:'🏃',diff:'Nybörjare',type:'Kondition',isTimer:true,instructions:['Ställ önskad hastighet','Håll upprätt hållning','Titta rakt fram','Anpassa fart efter syfte (gång/löpning/intervall)']},
+  {id:'stationary_bike',name:'Stationary Bike',muscle:'Kondition',secondary:'Ben',equip:'Maskin',icon:'🚴',diff:'Nybörjare',type:'Kondition',isTimer:true,instructions:['Justera sadelhöjd, benen nästan raka vid botten','Håll upprätt hållning','Pedala med jämnt motstånd','Anpassa intensitet efter syfte']},
+];
+
+const EQUIP_CHIPS=['Kroppsvikt','Hantel','Kettlebell','Skivstång','Kabelmaskin','Maskin','Motståndsband','Löpband'];
+const MUSCLE_FILTER=['Alla','Bröst','Rygg','Ben','Axlar','Armar','Core','Helkropp','Kondition'];
+
+// ── FOODS (per 100g) ──────────────────────────────────────
+const FOODS=[
+  // Kött & Fisk
+  {id:'chicken_breast',  name:'Kycklingfilé',           cal:165, prot:31,  carbs:0,   fat:3.6},
+  {id:'ground_beef',     name:'Nötfärs (10%)',           cal:152, prot:20,  carbs:0,   fat:8},
+  {id:'salmon',          name:'Lax',                     cal:208, prot:20,  carbs:0,   fat:13},
+  {id:'tuna_canned',     name:'Tonfisk (konserv)',        cal:116, prot:26,  carbs:0,   fat:1},
+  {id:'egg',             name:'Ägg',                     cal:155, prot:13,  carbs:1.1, fat:11},
+  {id:'shrimp',          name:'Räkor',                   cal:99,  prot:21,  carbs:0,   fat:1.1},
+  // Mejeri
+  {id:'milk',            name:'Mjölk (3%)',               cal:61,  prot:3.2, carbs:4.7, fat:3},
+  {id:'greek_yogurt',    name:'Grekisk yoghurt (0%)',     cal:59,  prot:10,  carbs:3.6, fat:0.4},
+  {id:'cottage_cheese',  name:'Keso',                    cal:72,  prot:12,  carbs:2.7, fat:1},
+  {id:'cheddar',         name:'Ost (28%)',                cal:280, prot:25,  carbs:0,   fat:20},
+  {id:'quark',           name:'Kvarg',                   cal:66,  prot:10.5,carbs:3.8, fat:0.2},
+  // Spannmål
+  {id:'oats',            name:'Havregryn',               cal:389, prot:17,  carbs:66,  fat:7},
+  {id:'rice_cooked',     name:'Ris (kokt)',               cal:130, prot:2.7, carbs:28,  fat:0.3},
+  {id:'pasta_cooked',    name:'Pasta (kokt)',             cal:131, prot:5,   carbs:25,  fat:1.1},
+  {id:'white_bread',     name:'Vitt bröd',               cal:265, prot:9,   carbs:49,  fat:3.2},
+  {id:'rye_bread',       name:'Rågbröd',                 cal:259, prot:9,   carbs:45,  fat:3.3},
+  {id:'tortilla',        name:'Tortillabröd',            cal:303, prot:8,   carbs:52,  fat:6.7},
+  // Grönsaker
+  {id:'broccoli',        name:'Broccoli',                cal:34,  prot:2.8, carbs:7,   fat:0.4},
+  {id:'spinach',         name:'Spenat',                  cal:23,  prot:2.9, carbs:3.6, fat:0.4},
+  {id:'potato',          name:'Potatis (kokt)',           cal:87,  prot:2.1, carbs:19,  fat:0.1},
+  {id:'sweet_potato',    name:'Sötpotatis',              cal:86,  prot:1.6, carbs:20,  fat:0.1},
+  // Frukt
+  {id:'banana',          name:'Banan',                   cal:89,  prot:1.1, carbs:23,  fat:0.3},
+  {id:'apple',           name:'Äpple',                   cal:52,  prot:0.3, carbs:14,  fat:0.2},
+  {id:'blueberry',       name:'Blåbär',                  cal:57,  prot:0.7, carbs:14,  fat:0.3},
+  // Nötter & övrigt
+  {id:'almonds',         name:'Mandlar',                 cal:579, prot:21,  carbs:22,  fat:50},
+  {id:'peanut_butter',   name:'Jordnötssmör',            cal:588, prot:25,  carbs:20,  fat:50},
+  {id:'olive_oil',       name:'Olivolja',                cal:884, prot:0,   carbs:0,   fat:100},
+  {id:'avocado',         name:'Avokado',                 cal:160, prot:2,   carbs:9,   fat:15},
+  {id:'protein_powder',  name:'Proteinpulver (vanilj)',  cal:390, prot:75,  carbs:10,  fat:5},
+  {id:'kidney_beans',    name:'Kidneybönor (kokt)',      cal:127, prot:8.7, carbs:22,  fat:0.5},
+];
+
+// ── THEMES ────────────────────────────────────────────────
+const THEMES={
+  fortis:{
+    name:'Fortis',
+    accent:'#E85D26', accent2:'#2A6AE8', accentLight:'#FEF0EB',
+    bg:'#F2F1ED', card:'#FFFFFF', text:'#141414', muted:'#888880',
+    border:'rgba(0,0,0,0.09)', nav:'#FFFFFF', header:'#141414',
+    headerText:'#FFFFFF', outer:'#E8E6E0',
+  },
+  dark:{
+    name:'Dark',
+    accent:'#E85D26', accent2:'#4A8AFF', accentLight:'#2A1A14',
+    bg:'#121212', card:'#1E1E1E', text:'#F0F0EC', muted:'#777770',
+    border:'rgba(255,255,255,0.08)', nav:'#1A1A1A', header:'#0A0A0A',
+    headerText:'#F0F0EC', outer:'#090909',
+  },
+  midnight:{
+    name:'Midnight',
+    accent:'#5B8BFF', accent2:'#E85D26', accentLight:'#131B2E',
+    bg:'#0D1117', card:'#161B22', text:'#E6EDF3', muted:'#7D8590',
+    border:'rgba(255,255,255,0.08)', nav:'#161B22', header:'#0D1117',
+    headerText:'#E6EDF3', outer:'#080B10',
+  },
+  forest:{
+    name:'Forest',
+    accent:'#2D9E5F', accent2:'#2A6AE8', accentLight:'#E6F7ED',
+    bg:'#F0F4F0', card:'#FFFFFF', text:'#1A2E1A', muted:'#6A7A6A',
+    border:'rgba(0,0,0,0.08)', nav:'#FFFFFF', header:'#1A2E1A',
+    headerText:'#FFFFFF', outer:'#E4EAE4',
+  },
+  stone:{
+    name:'Stone',
+    accent:'#6366F1', accent2:'#EC4899', accentLight:'#EDEDFD',
+    bg:'#F5F5F4', card:'#FFFFFF', text:'#1C1917', muted:'#78716C',
+    border:'rgba(0,0,0,0.08)', nav:'#FFFFFF', header:'#1C1917',
+    headerText:'#FFFFFF', outer:'#E7E5E4',
+  },
+};
+
+function applyTheme(id){
+  const t=THEMES[id]||THEMES.fortis;
+  const r=document.documentElement.style;
+  r.setProperty('--accent',t.accent);
+  r.setProperty('--accent2',t.accent2);
+  r.setProperty('--accent-light',t.accentLight);
+  r.setProperty('--bg',t.bg);
+  r.setProperty('--card',t.card);
+  r.setProperty('--text',t.text);
+  r.setProperty('--muted',t.muted);
+  r.setProperty('--border',t.border);
+  r.setProperty('--nav',t.nav);
+  r.setProperty('--header',t.header);
+  r.setProperty('--header-text',t.headerText);
+  r.setProperty('--outer',t.outer);
+  document.body.style.background=t.outer;
+  ST.activeTheme=id;
+}
+
+async function setTheme(id){
+  applyTheme(id);
+  await save('fortis_theme',id);
+  renderProfile();
+}
+
+// ── ACHIEVEMENTS ──────────────────────────────────────────
+const ACHIEVEMENT_DEFS=[
+  {id:'first_workout',  icon:'🏋️', name:'Första passet',    desc:'Slutför ditt första pass'},
+  {id:'workouts_10',    icon:'💪',  name:'10 pass',          desc:'Slutför 10 pass totalt'},
+  {id:'workouts_50',    icon:'🏆',  name:'50 pass',          desc:'Slutför 50 pass totalt'},
+  {id:'workouts_100',   icon:'🥇',  name:'100 pass',         desc:'Slutför 100 pass totalt'},
+  {id:'streak_3',       icon:'🔥',  name:'3 i rad',          desc:'3 dagars träningsstreak'},
+  {id:'streak_7',       icon:'🔥',  name:'Vecka på raken',   desc:'7 dagars träningsstreak'},
+  {id:'streak_30',      icon:'🔥',  name:'Månadsstreak',     desc:'30 dagars träningsstreak'},
+  {id:'early_bird',     icon:'🌅',  name:'Tidig fågel',      desc:'Logga ett pass före 08:00'},
+  {id:'variety',        icon:'🌟',  name:'Allrounder',       desc:'Träna 5 olika muskelgrupper'},
+  {id:'marathon',       icon:'⏱️',  name:'Uthållighet',      desc:'Slutför ett pass längre än 60 min'},
+];
+
+function calcBestStreak(){
+  if(!ST.workoutLog.length)return 0;
+  const dates=[...new Set(ST.workoutLog.map(l=>l.date))].sort();
+  let best=1,cur=1;
+  for(let i=1;i<dates.length;i++){
+    const diff=(new Date(dates[i])-new Date(dates[i-1]))/86400000;
+    if(diff===1){cur++;best=Math.max(best,cur);}else cur=1;
+  }
+  return best;
+}
+
+function evalAchievements(){
+  const unlocked=new Set(ST.achievements||[]);
+  const toUnlock=[];
+  const total=ST.workoutLog.length;
+  const streak=calcStreak();
+  const best=calcBestStreak();
+
+  const check=(id,cond)=>{if(cond&&!unlocked.has(id))toUnlock.push(id);};
+
+  check('first_workout', total>=1);
+  check('workouts_10',   total>=10);
+  check('workouts_50',   total>=50);
+  check('workouts_100',  total>=100);
+  check('streak_3',      streak>=3||best>=3);
+  check('streak_7',      streak>=7||best>=7);
+  check('streak_30',     streak>=30||best>=30);
+  check('variety', (()=>{
+    const muscles=new Set();
+    for(const entry of ST.workoutLog){
+      const w=ST.workouts.find(x=>x.id===entry.workoutId);
+      if(!w)continue;
+      w.exercises.forEach(e=>{const ex=getExercises().find(x=>x.id===e.exerciseId);if(ex)muscles.add(ex.muscle);});
+    }
+    return muscles.size>=5;
+  })());
+  check('early_bird', ST.workoutLog.some(e=>{
+    const h=new Date(e.id).getHours();return h<8;
+  }));
+  check('marathon', ST.workoutLog.some(e=>e.durationMin>=60));
+
+  return toUnlock;
+}
+
+async function checkAchievements(){
+  const newOnes=evalAchievements();
+  if(!newOnes.length)return;
+  ST.achievements=[...(ST.achievements||[]),...newOnes];
+  await save('fortis_achievements',ST.achievements);
+  for(const id of newOnes){
+    const def=ACHIEVEMENT_DEFS.find(a=>a.id===id);
+    if(def)showAchievementToast(def);
+    await new Promise(r=>setTimeout(r,2200));
+  }
+}
+
+function showAchievementToast(def){
+  const el=document.getElementById('achievementToast');
+  el.innerHTML=`<div style="font-size:28px;margin-bottom:4px">${def.icon}</div>
+    <div style="font-size:11px;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;color:var(--accent);margin-bottom:2px">Achievement unlocked</div>
+    <div style="font-size:15px;font-weight:800;color:var(--text)">${def.name}</div>
+    <div style="font-size:12px;color:var(--muted);margin-top:2px">${def.desc}</div>`;
+  el.classList.add('show');
+  setTimeout(()=>el.classList.remove('show'),2000);
+}
+
+// ── STATE ─────────────────────────────────────────────────
+let ST={
+  profile:null,
+  activeTheme:'fortis',
+  obStep:1,
+  obData:{name:'',gender:'male',age:'',height:'',weight:'',goalWeight:'',goal:'lose',activity:'moderate'},
+  macroGoals:{calories:2200,protein:165,carbs:220,fat:73},
+  waterToday:0,
+  waterGoal:2500,
+  activeTab:'Home',
+  selectedDay:new Date().getDay()==0?0:new Date().getDay()-1,
+  workouts:[],
+  workoutLog:[],
+  achievements:[],
+  foodLog:[],
+  _addFoodMeal:null,
+  _addFoodSelected:null,
+  activeWorkout:null,
+  awStartTime:null,
+  awTimerInterval:null,
+  restInterval:null,
+  equipFilter:[],
+  muscleFilter:'Alla',
+  diffFilter:'Alla',
+  searchQ:'',
+  customExercises:[],
+  _createExInstructions:[],
+};
+
+// ── STORAGE ───────────────────────────────────────────────
+async function load(key,def=null){
+  if(!window.storage)return def;
+  try{const r=await window.storage.get(key);return r?JSON.parse(r.value):def;}catch{return def;}
+}
+async function save(key,val){
+  if(!window.storage)return;
+  try{await window.storage.set(key,JSON.stringify(val));}catch{}
+}
+
+// ── INIT ──────────────────────────────────────────────────
+async function init(){
+  ST.profile=await load('fortis_profile');
+  ST.waterToday=await load('fortis_water_'+today(),0);
+  ST.workouts=await load('fortis_workouts',defaultWorkouts());
+  ST.workoutLog=await load('fortis_workoutlog',[]);
+  ST.achievements=await load('fortis_achievements',[]);
+  ST.foodLog=await load('fortis_foodlog',[]);
+  ST.customExercises=await load('fortis_custom_exercises',[]);
+  const savedTheme=await load('fortis_theme','fortis');
+  applyTheme(savedTheme);
+  startSplash();
+}
+
+function today(){return new Date().toISOString().slice(0,10);}
+
+function defaultWorkouts(){
+  return[
+    {id:'w1',name:'Hemmapass',day:0,exercises:[
+      {exerciseId:'situp',sets:3,reps:30,weight:0,restSec:60},
+      {exerciseId:'pushup',sets:3,reps:20,weight:0,restSec:60},
+      {exerciseId:'squat',sets:3,reps:20,weight:20,restSec:90},
+      {exerciseId:'plank',sets:1,durationSec:60,weight:0,restSec:60},
+      {exerciseId:'dumbbell_curl',sets:3,reps:15,weight:12,restSec:60},
+    ]},
+    {id:'w2',name:'Konditionspass',day:2,exercises:[
+      {exerciseId:'burpee',sets:3,reps:12,weight:0,restSec:90},
+      {exerciseId:'lunges',sets:3,reps:20,weight:0,restSec:60},
+      {exerciseId:'russian_twist',sets:3,reps:30,weight:0,restSec:45},
+    ]},
+    {id:'w3',name:'Rygg & Biceps',day:4,exercises:[
+      {exerciseId:'pullup',sets:3,reps:8,weight:0,restSec:120},
+      {exerciseId:'cable_row',sets:3,reps:12,weight:40,restSec:90},
+      {exerciseId:'dumbbell_curl',sets:3,reps:12,weight:14,restSec:60},
+    ]},
+  ];
+}
+
+// ── SPLASH ────────────────────────────────────────────────
+function startSplash(){
+  document.getElementById('splash').style.display='flex';
+  const fill=document.getElementById('splashFill');
+  let p=0;
+  const iv=setInterval(()=>{
+    p+=100/30;fill.style.width=Math.min(p,100)+'%';
+    if(p>=100){clearInterval(iv);endSplash();}
+  },100);
+}
+function endSplash(){
+  document.getElementById('splash').style.opacity='0';
+  document.getElementById('splash').style.transition='opacity 0.4s';
+  setTimeout(()=>{
+    document.getElementById('splash').style.display='none';
+    if(ST.profile){showApp();}else{showOnboarding();}
+  },400);
+}
+
+// ── ONBOARDING ────────────────────────────────────────────
+const OB=[
+  {title:'Välkommen till FORTIS',desc:'Din personliga träningskompis. Sätt upp mål, följ din progress och bli starkare — varje dag.',btn:'Kom igång'},
+  {title:'Om dig',desc:'Vi behöver lite grundläggande info för att anpassa appen till dig.',btn:'Nästa'},
+  {title:'Ditt mål',desc:'Berätta vad du vill uppnå och hur aktiv du är till vardags.',btn:'Beräkna mål'},
+  {title:'Kalori- och makromål',desc:'Baserat på din info har vi räknat ut ditt dagliga mål. Du kan justera det manuellt.',btn:'Acceptera'},
+  {title:'Allt klart!',desc:'',btn:'Starta FORTIS'},
+];
+
+function showOnboarding(){
+  document.getElementById('onboarding').style.display='block';
+  renderOB();
+}
+function renderOB(){
+  const s=ST.obStep;
+  document.getElementById('obSteps').innerHTML=OB.map((_,i)=>`<div class="ob-step${i<s?' done':''}"></div>`).join('');
+  document.getElementById('obTitle').textContent=OB[s-1].title;
+  document.getElementById('obDesc').textContent=OB[s-1].desc;
+  const backBtn=s>1&&s<5?'<button class="btn-ghost" onclick="obBack()">Tillbaka</button>':'';
+  const skipBtn=s===1?'<button class="btn-ghost" onclick="skipOnboarding()">Hoppa över</button>':'';
+  document.getElementById('obFooter').innerHTML=`<button class="btn-primary" onclick="obNext()">${OB[s-1].btn}</button>${backBtn}${skipBtn}`;
+  const body=document.getElementById('obBody');
+  if(s===1){body.innerHTML=`<div style="text-align:center;padding:32px 0"><div style="font-size:64px;margin-bottom:16px">💪</div><p style="font-size:15px;color:var(--muted);line-height:1.7">Logga pass · Spåra kost · Se din progress</p></div>`;}
+  else if(s===2){body.innerHTML=`
+    <div class="field"><label>Namn</label><input type="text" value="${ST.obData.name}" placeholder="Ditt namn" oninput="ST.obData.name=this.value"></div>
+    <div class="field"><label>Kön</label><div class="radio-group">
+      <div class="radio-opt ${ST.obData.gender==='male'?'active':''}" onclick="setOBField('gender','male',this,'radio-opt')">Man</div>
+      <div class="radio-opt ${ST.obData.gender==='female'?'active':''}" onclick="setOBField('gender','female',this,'radio-opt')">Kvinna</div>
+      <div class="radio-opt ${ST.obData.gender==='other'?'active':''}" onclick="setOBField('gender','other',this,'radio-opt')">Annat</div>
+    </div></div>
+    <div class="field"><label>Ålder</label><input type="number" value="${ST.obData.age}" placeholder="år" oninput="ST.obData.age=this.value" min="10" max="99"></div>`;}
+  else if(s===3){body.innerHTML=`
+    <div class="field-row">
+      <div class="field"><label>Längd (cm)</label><input type="number" value="${ST.obData.height}" placeholder="cm" oninput="ST.obData.height=this.value" min="140" max="220"></div>
+      <div class="field"><label>Vikt (kg)</label><input type="number" value="${ST.obData.weight}" placeholder="kg" oninput="ST.obData.weight=this.value" min="40" max="200"></div>
+    </div>
+    <div class="field"><label>Målvikt (kg)</label><input type="number" value="${ST.obData.goalWeight}" placeholder="kg" oninput="ST.obData.goalWeight=this.value"></div>
+    <div class="field"><label>Mål</label><div class="radio-group">
+      <div class="radio-opt ${ST.obData.goal==='lose'?'active':''}" onclick="setOBField('goal','lose',this,'radio-opt')">Gå ner</div>
+      <div class="radio-opt ${ST.obData.goal==='maintain'?'active':''}" onclick="setOBField('goal','maintain',this,'radio-opt')">Hålla vikt</div>
+      <div class="radio-opt ${ST.obData.goal==='gain'?'active':''}" onclick="setOBField('goal','gain',this,'radio-opt')">Bygga muskler</div>
+    </div></div>
+    <div class="field"><label>Aktivitetsnivå</label><select onchange="ST.obData.activity=this.value">
+      <option value="sedentary" ${ST.obData.activity==='sedentary'?'selected':''}>Stillasittande (lite/ingen träning)</option>
+      <option value="light" ${ST.obData.activity==='light'?'selected':''}>Lätt aktiv (1–3 dagar/vecka)</option>
+      <option value="moderate" ${ST.obData.activity==='moderate'?'selected':''}>Måttligt aktiv (3–5 dagar/vecka)</option>
+      <option value="very_active" ${ST.obData.activity==='very_active'?'selected':''}>Mycket aktiv (6–7 dagar/vecka)</option>
+    </select></div>`;}
+  else if(s===4){
+    calcMacros();
+    body.innerHTML=`
+    <div class="macro-preview">
+      <div class="macro-row"><span class="macro-name">Kalorier</span><span class="macro-val">${ST.macroGoals.calories}<span class="macro-unit"> kcal</span></span></div>
+      <div class="macro-row"><span class="macro-name">Protein</span><span class="macro-val">${ST.macroGoals.protein}<span class="macro-unit"> g</span></span></div>
+      <div class="macro-row"><span class="macro-name">Kolhydrater</span><span class="macro-val">${ST.macroGoals.carbs}<span class="macro-unit"> g</span></span></div>
+      <div class="macro-row"><span class="macro-name">Fett</span><span class="macro-val">${ST.macroGoals.fat}<span class="macro-unit"> g</span></span></div>
+    </div>
+    <p style="font-size:13px;color:var(--muted);margin-top:14px;line-height:1.6">Beräknat med Mifflin-St Jeor-formeln. Du kan justera detta när som helst under Profil → Inställningar.</p>`;}
+  else if(s===5){body.innerHTML=`<div class="done-screen"><div class="done-icon">🚀</div><div class="done-title">Dags att köra, ${ST.obData.name||'champ'}!</div><div class="done-sub">Ditt program är klart. Börja med att kolla in ditt schema och hoppa in i ditt första pass.</div></div>`;}
+}
+
+function setOBField(field,val,el,cls){
+  ST.obData[field]=val;
+  document.querySelectorAll('.'+cls).forEach(e=>e.classList.remove('active'));
+  el.classList.add('active');
+}
+
+function calcMacros(){
+  const d=ST.obData;
+  const w=parseFloat(d.weight)||80,h=parseFloat(d.height)||175,a=parseInt(d.age)||30;
+  let bmr=d.gender==='female'?(10*w+6.25*h-5*a-161):(10*w+6.25*h-5*a+5);
+  const mult={sedentary:1.2,light:1.375,moderate:1.55,very_active:1.725}[d.activity]||1.55;
+  let tdee=Math.round(bmr*mult);
+  if(d.goal==='lose')tdee-=400;
+  if(d.goal==='gain')tdee+=300;
+  ST.macroGoals={
+    calories:tdee,
+    protein:Math.round(w*2.2),
+    carbs:Math.round((tdee*0.4)/4),
+    fat:Math.round((tdee*0.3)/9),
+  };
+}
+
+function obNext(){
+  if(ST.obStep===5){saveProfile();showApp();return;}
+  ST.obStep++;renderOB();
+}
+function obBack(){ST.obStep--;renderOB();}
+async function skipOnboarding(){
+  ST.obData={name:'',gender:'male',age:25,height:175,weight:75,goalWeight:75,goal:'maintain',activity:'moderate'};
+  ST.macroGoals={calories:2200,protein:165,carbs:220,fat:73};
+  await saveProfile();
+  showApp();
+}
+
+async function saveProfile(){
+  ST.profile={...ST.obData,macroGoals:ST.macroGoals,createdAt:new Date().toISOString()};
+  await save('fortis_profile',ST.profile);
+  await save('fortis_macrogoals',ST.macroGoals);
+  document.getElementById('onboarding').style.display='none';
+}
+
+// ── MAIN APP ──────────────────────────────────────────────
+function showApp(){
+  document.getElementById('onboarding').style.display='none';
+  const app=document.getElementById('app');
+  app.style.display='flex';
+  if(ST.profile){
+    const m=ST.profile.macroGoals||ST.macroGoals;
+    ST.macroGoals=m;
+  }
+  renderHome();
+  renderScheduleSetup();
+  renderLibrary();
+  renderNutrition();
+  renderProfile();
+}
+
+function switchTab(tab){
+  ['Home','Schedule','Library','Nutrition','Profile'].forEach(t=>{
+    document.getElementById('tab'+t).style.display=t===tab?'':'none';
+    document.getElementById('nav'+t).classList.toggle('active',t===tab);
+  });
+  ST.activeTab=tab;
+}
+
+// ── HOME ──────────────────────────────────────────────────
+function renderHome(){
+  const p=ST.profile||{name:'Jens'};
+  document.getElementById('homeGreeting').textContent=p.name||'Jens';
+  document.getElementById('streakCount').textContent=calcStreak();
+  renderCalorieRing(0,ST.macroGoals.calories);
+  renderMacros(0,0,0);
+  renderWater();
+  renderTodayWorkout();
+}
+
+function renderCalorieRing(consumed,goal){
+  const left=Math.max(0,goal-consumed);
+  document.getElementById('calsLeft').textContent=left;
+  const pct=Math.min(consumed/goal,1);
+  const circ=264;
+  document.getElementById('calRing').style.strokeDashoffset=circ-(circ*pct);
+}
+
+function renderMacros(p,c,f){
+  document.getElementById('mProtein').innerHTML=`${p}<span class="rm-unit">g</span>`;
+  document.getElementById('mCarbs').innerHTML=`${c}<span class="rm-unit">g</span>`;
+  document.getElementById('mFat').innerHTML=`${f}<span class="rm-unit">g</span>`;
+  document.getElementById('mProteinBar').style.width=Math.min(p/ST.macroGoals.protein*100,100)+'%';
+  document.getElementById('mCarbsBar').style.width=Math.min(c/ST.macroGoals.carbs*100,100)+'%';
+  document.getElementById('mFatBar').style.width=Math.min(f/ST.macroGoals.fat*100,100)+'%';
+}
+
+function renderWater(){
+  const portions=10;
+  const filled=Math.round((ST.waterToday/ST.waterGoal)*portions);
+  document.getElementById('waterDrops').innerHTML=Array.from({length:portions},(_,i)=>`<div class="drop ${i<filled?'filled':''}"></div>`).join('');
+  document.getElementById('waterLabel').textContent=`${ST.waterToday} / ${ST.waterGoal} ml`;
+}
+
+async function addWater(){
+  ST.waterToday=Math.min(ST.waterToday+250,ST.waterGoal);
+  await save('fortis_water_'+today(),ST.waterToday);
+  renderWater();
+}
+
+function renderTodayWorkout(){
+  const dow=new Date().getDay()==0?6:new Date().getDay()-1;
+  const w=ST.workouts.find(x=>x.day===dow);
+  const card=document.getElementById('todayWorkoutCard');
+  if(!w){card.innerHTML=`<div class="no-workout">Ingen träning schemalagd idag 😴<br><span style="font-size:12px">Lägg till ett pass i Schema</span></div>`;return;}
+  const exs=w.exercises.map(e=>getExercises().find(x=>x.id===e.exerciseId)).filter(Boolean);
+  const muscles=[...new Set(exs.map(e=>e.muscle))];
+  card.innerHTML=`
+  <div class="workout-card-inner">
+    <div style="flex:1;min-width:0">
+      <div class="workout-name">${w.name}</div>
+      <div class="workout-meta">${w.exercises.length} övningar · ~${w.exercises.length*8} min</div>
+      <div class="muscle-badges">${muscles.map((m,i)=>`<span class="badge ${['badge-orange','badge-blue','badge-green'][i%3]}">${m}</span>`).join('')}</div>
+    </div>
+    <button class="btn-start" onclick="startWorkout('${w.id}')">Starta</button>
+  </div>`;
+}
+
+function calcStreak(){
+  if(!ST.workoutLog.length)return 0;
+  let s=0;const d=new Date();
+  while(true){
+    const key=d.toISOString().slice(0,10);
+    if(ST.workoutLog.some(l=>l.date===key)){s++;d.setDate(d.getDate()-1);}
+    else break;
+  }
+  return s;
+}
+
+// ── SCHEDULE ─────────────────────────────────────────────
+function renderScheduleSetup(){
+  const days=['Mån','Tis','Ons','Tor','Fre','Lör','Sön'];
+  const todayDow=new Date().getDay()==0?6:new Date().getDay()-1;
+  const strip=document.getElementById('weekStrip');
+  strip.innerHTML=days.map((d,i)=>{
+    const hasW=ST.workouts.some(w=>w.day===i);
+    return`<div class="day-pill ${i===ST.selectedDay?'active':''}" onclick="selectDay(${i})">
+      <div class="day-name">${d}</div>
+      <div class="day-num" style="${i===todayDow?'color:#E85D26':''}">${i+1}</div>
+      ${hasW?'<div class="day-dot"></div>':'<div style="width:4px;height:4px"></div>'}
+    </div>`;
+  }).join('');
+  renderDaySchedule();
+}
+
+function selectDay(i){
+  ST.selectedDay=i;renderScheduleSetup();}
+
+function renderDaySchedule(){
+  const days=['Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag','Söndag'];
+  const body=document.getElementById('schedBody');
+  const ws=ST.workouts.filter(w=>w.day===ST.selectedDay);
+  let html=`<div class="day-title">${days[ST.selectedDay]}</div>`;
+  ws.forEach(w=>{
+    const exs=w.exercises.map(e=>({...e,ex:getExercises().find(x=>x.id===e.exerciseId)})).filter(e=>e.ex);
+    html+=`<div class="workout-block">
+      <div class="wb-header"><div class="wb-name">${w.name}</div><div class="wb-time">${w.exercises.length} övn · ~${w.exercises.length*8} min</div></div>
+      <div class="wb-exercises">
+        ${exs.map(e=>`<div class="wb-ex"><div class="wb-ex-dot"></div>${e.ex.name}<div class="wb-ex-detail">${e.sets}×${e.reps||e.durationSec+'s'}${e.weight?' @ '+e.weight+'kg':''}</div></div>`).join('')}
+      </div>
+      <div class="wb-footer"><button class="btn-start-full" onclick="startWorkout('${w.id}')">Starta pass</button></div>
+    </div>`;
+  });
+  html+=`<button class="add-workout-btn" onclick="showAddWorkout()">+ Lägg till pass</button>`;
+  body.innerHTML=html;
+}
+
+function showAddWorkout(){
+  document.getElementById('modalTitle').textContent='Nytt pass';
+  document.getElementById('modalBody').innerHTML=`
+    <div class="field"><label>Passnamn</label><input type="text" id="newWName" placeholder="t.ex. Benstyrka"></div>
+    <p style="font-size:13px;color:var(--muted);margin-bottom:16px">Övningar läggs till från biblioteket efter att passet skapats.</p>
+    <button class="btn-primary" onclick="createWorkout()">Skapa pass</button>`;
+  document.getElementById('modalOverlay').classList.add('show');
+}
+
+function createWorkout(){
+  const name=document.getElementById('newWName').value.trim();
+  if(!name)return;
+  const w={id:'w'+Date.now(),name,day:ST.selectedDay,exercises:[]};
+  ST.workouts.push(w);
+  save('fortis_workouts',ST.workouts);
+  closeModal();
+  renderScheduleSetup();
+}
+
+// ── LIBRARY ───────────────────────────────────────────────
+function getExercises(){return[...EXERCISES,...ST.customExercises];}
+
+function renderLibrary(){
+  const chips=document.getElementById('equipChips');
+  chips.innerHTML=EQUIP_CHIPS.map(c=>`<div class="chip ${ST.equipFilter.includes(c)?'active':''}" onclick="toggleChip('${c}')">${c}</div>`).join('');
+  updateFilterBadge();
+  filterExercises();
+}
+
+function toggleChip(c){
+  ST.equipFilter=ST.equipFilter.includes(c)?ST.equipFilter.filter(x=>x!==c):[...ST.equipFilter,c];
+  renderLibrary();
+}
+
+function updateFilterBadge(){
+  const count=(ST.muscleFilter!=='Alla'?1:0)+(ST.diffFilter!=='Alla'?1:0);
+  const badge=document.getElementById('filterBadge');
+  if(!badge)return;
+  if(count>0){badge.textContent=count;badge.style.display='inline';}
+  else{badge.style.display='none';}
+}
+
+function filterExercises(){
+  ST.searchQ=document.getElementById('libSearch')?.value.toLowerCase()||'';
+  let exs=getExercises();
+  if(ST.equipFilter.length)exs=exs.filter(e=>ST.equipFilter.includes(e.equip));
+  if(ST.muscleFilter!=='Alla')exs=exs.filter(e=>e.muscle===ST.muscleFilter);
+  if(ST.diffFilter!=='Alla')exs=exs.filter(e=>e.diff===ST.diffFilter);
+  if(ST.searchQ)exs=exs.filter(e=>e.name.toLowerCase().includes(ST.searchQ));
+  const colors={'Kroppsvikt':'#FEF0EB','Hantel':'#EBF0FE','Kettlebell':'#EAFAEE','Skivstång':'#FFF8E6','Kabelmaskin':'#F3EBFE','Maskin':'#F0F0EE'};
+  document.getElementById('libBody').innerHTML=exs.length?
+    exs.map(e=>`<div class="ex-card${e.isCustom?' ex-card-custom':''}" onclick="showExercise('${e.id}')">
+      <div class="ex-icon" style="background:${colors[e.equip]||'#F5F5F3'}">${e.icon||'⚡'}</div>
+      <div class="ex-info">
+        <div class="ex-name">${e.name}${e.isCustom?'<span style="font-size:10px;font-weight:700;color:var(--accent);margin-left:6px">EGEN</span>':''}</div>
+        <div class="ex-meta">${e.muscle} · ${e.diff}</div>
+      </div>
+      <div class="ex-equip">${e.equip}</div>
+    </div>`).join('')
+    :'<div style="text-align:center;padding:32px;color:var(--muted)">Inga övningar hittades</div>';
+}
+
+function showExercise(id){
+  const e=getExercises().find(x=>x.id===id);if(!e)return;
+  document.getElementById('modalTitle').textContent=e.name;
+  document.getElementById('modalBody').innerHTML=`
+    <div style="display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap">
+      <span class="badge badge-orange">${e.muscle}</span>
+      <span class="badge badge-blue">${e.equip}</span>
+      <span class="badge" style="background:var(--bg);color:var(--muted)">${e.diff}</span>
+    </div>
+    <div style="font-size:13px;color:var(--muted);margin-bottom:4px;font-weight:600;text-transform:uppercase;letter-spacing:0.06em">Sekundära muskler</div>
+    <div style="font-size:14px;color:var(--text);margin-bottom:16px">${e.secondary||'—'}</div>
+    <div style="font-size:13px;color:var(--muted);margin-bottom:8px;font-weight:600;text-transform:uppercase;letter-spacing:0.06em">Utförande</div>
+    ${e.instructions.map((s,i)=>`<div style="display:flex;gap:10px;margin-bottom:8px"><div style="width:22px;height:22px;border-radius:50%;background:var(--accent);color:#FFF;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0">${i+1}</div><div style="font-size:14px;color:var(--text);line-height:1.5">${s}</div></div>`).join('')}
+    <button class="btn-primary" style="margin-top:20px" onclick="showProgression('${id}')">📈 Se progression</button>
+    ${e.isCustom?`<button class="btn-ghost" style="color:#E53E3E;border-color:#E53E3E;margin-top:8px" onclick="deleteCustomExercise('${id}')">🗑 Ta bort övning</button>`:''}
+    <button class="btn-ghost" onclick="closeModal()">Stäng</button>`;
+  document.getElementById('modalOverlay').classList.add('show');
+}
+
+function getExerciseProgression(exId){
+  const points=[];
+  const sorted=[...ST.workoutLog].sort((a,b)=>a.date<b.date?-1:1);
+  for(const entry of sorted){
+    const workout=ST.workouts.find(w=>w.id===entry.workoutId);
+    if(!workout)continue;
+    const exIdx=workout.exercises.findIndex(e=>e.exerciseId===exId);
+    if(exIdx===-1)continue;
+    const sets=(entry.exercises||[])[exIdx];
+    if(!sets||!sets.length)continue;
+    const done=sets.filter(s=>s.done);
+    if(!done.length)continue;
+    const maxW=Math.max(...done.map(s=>s.weight||0));
+    const maxR=Math.max(...done.map(s=>s.reps||0));
+    const vol=done.reduce((sum,s)=>sum+(s.reps||0)*(s.weight||0),0);
+    points.push({date:entry.date,maxW,maxR,vol,sets:done.length});
+  }
+  return points;
+}
+
+function buildProgressionSVG(points,isBodyweight){
+  const W=300,H=140,PL=36,PR=8,PT=10,PB=28;
+  const PW=W-PL-PR,PH=H-PT-PB;
+  const vals=points.map(p=>isBodyweight?p.maxR:p.maxW||p.maxR);
+  const maxV=Math.max(...vals,1)*1.15;
+  const prIdx=vals.indexOf(Math.max(...vals));
+  const xs=points.map((_,i)=>PL+(points.length>1?i/(points.length-1)*PW:PW/2));
+  const ys=vals.map(v=>PT+PH-(v/maxV)*PH);
+  const line=xs.map((x,i)=>`${i?'L':'M'}${x.toFixed(1)},${ys[i].toFixed(1)}`).join('');
+  const area=`${line}L${xs[xs.length-1].toFixed(1)},${PT+PH}L${xs[0].toFixed(1)},${PT+PH}Z`;
+  const grid=[0.25,0.5,0.75,1].map(f=>{
+    const y=PT+PH-f*PH;
+    return`<line x1="${PL}" y1="${y.toFixed(1)}" x2="${W-PR}" y2="${y.toFixed(1)}" stroke="var(--border)" stroke-width="1"/>
+    <text x="${PL-4}" y="${(y+3.5).toFixed(1)}" text-anchor="end" font-size="9" fill="var(--muted)">${Math.round(f*maxV)}</text>`;
+  }).join('');
+  const step=Math.ceil(points.length/5);
+  const xlabels=points.map((p,i)=>{
+    if(i%step!==0&&i!==points.length-1)return'';
+    return`<text x="${xs[i].toFixed(1)}" y="${PT+PH+16}" text-anchor="middle" font-size="8" fill="var(--muted)">${p.date.slice(5)}</text>`;
+  }).join('');
+  const dots=xs.map((x,i)=>{
+    const pr=i===prIdx;
+    return`<circle cx="${x.toFixed(1)}" cy="${ys[i].toFixed(1)}" r="${pr?5.5:3.5}" fill="${pr?'var(--accent)':'var(--accent2)'}" stroke="white" stroke-width="1.5"/>`;
+  }).join('');
+  return`<svg viewBox="0 0 ${W} ${H}" style="width:100%;overflow:visible">
+    <defs><linearGradient id="ag" x1="0" y1="0" x2="0" y2="1">
+      <stop offset="0%" stop-color="var(--accent)" stop-opacity="0.18"/>
+      <stop offset="100%" stop-color="var(--accent)" stop-opacity="0"/>
+    </linearGradient></defs>
+    ${grid}
+    <line x1="${PL}" y1="${PT}" x2="${PL}" y2="${PT+PH}" stroke="var(--border)" stroke-width="1"/>
+    <line x1="${PL}" y1="${PT+PH}" x2="${W-PR}" y2="${PT+PH}" stroke="var(--border)" stroke-width="1"/>
+    ${xlabels}
+    <path d="${area}" fill="url(#ag)"/>
+    <path d="${line}" fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round"/>
+    ${dots}
+  </svg>`;
+}
+
+function showProgression(id){
+  const e=getExercises().find(x=>x.id===id);if(!e)return;
+  const points=getExerciseProgression(id);
+  const isBodyweight=e.equip==='Kroppsvikt'||e.isTimer;
+  const unit=isBodyweight?'reps':'kg';
+  const prVal=points.length?Math.max(...points.map(p=>isBodyweight?p.maxR:p.maxW||p.maxR)):0;
+  const lastVal=points.length?(isBodyweight?points[points.length-1].maxR:points[points.length-1].maxW||0):0;
+  document.getElementById('modalTitle').textContent=e.name;
+  document.getElementById('modalBody').innerHTML=`
+    <button onclick="showExercise('${id}')" style="background:none;border:none;color:var(--accent);font-size:13px;font-weight:600;cursor:pointer;padding:0;margin-bottom:16px">← Info</button>
+    <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:20px">
+      <div style="background:var(--bg);border-radius:var(--radius-sm);padding:12px;text-align:center">
+        <div style="font-size:20px;font-weight:800;color:var(--accent)">${prVal||'—'}</div>
+        <div style="font-size:10px;color:var(--muted);margin-top:2px">PR (${unit})</div>
+      </div>
+      <div style="background:var(--bg);border-radius:var(--radius-sm);padding:12px;text-align:center">
+        <div style="font-size:20px;font-weight:800;color:var(--text)">${points.length}</div>
+        <div style="font-size:10px;color:var(--muted);margin-top:2px">Pass</div>
+      </div>
+      <div style="background:var(--bg);border-radius:var(--radius-sm);padding:12px;text-align:center">
+        <div style="font-size:20px;font-weight:800;color:var(--text)">${lastVal||'—'}</div>
+        <div style="font-size:10px;color:var(--muted);margin-top:2px">Senast (${unit})</div>
+      </div>
+    </div>
+    <div style="font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:10px">${isBodyweight?'Max reps per pass':'Max vikt per pass (kg)'}</div>
+    ${points.length>=2
+      ? buildProgressionSVG(points,isBodyweight)
+      : `<div style="background:var(--bg);border-radius:var(--radius);padding:32px 16px;text-align:center;color:var(--muted);font-size:14px">${points.length===1?'Logga minst 2 pass för att se graf':'Inga loggade pass ännu'}</div>`}
+    <button class="btn-ghost" onclick="closeModal()" style="margin-top:16px">Stäng</button>`;
+}
+
+// ── NUTRITION ─────────────────────────────────────────────
+function todayFoodLog(){return ST.foodLog.filter(e=>e.date===today());}
+
+function foodMacros(f,g){
+  const r=g/100;
+  return{cal:Math.round(f.cal*r),prot:Math.round(f.prot*r*10)/10,carbs:Math.round(f.carbs*r*10)/10,fat:Math.round(f.fat*r*10)/10};
+}
+
+function renderNutrition(){
+  const d=new Date();
+  document.getElementById('nutrDate').textContent=d.toLocaleDateString('sv-SE',{weekday:'long',day:'numeric',month:'long'});
+  const log=todayFoodLog();
+  const g=ST.macroGoals;
+
+  const totals=log.reduce((s,e)=>({cal:s.cal+e.cal,prot:s.prot+e.prot,carbs:s.carbs+e.carbs,fat:s.fat+e.fat}),{cal:0,prot:0,carbs:0,fat:0});
+
+  const pctW=(v,max)=>Math.min(v/max*100,100).toFixed(1)+'%';
+
+  document.getElementById('nutrProtGoal').textContent=g.protein;
+  document.getElementById('nutrCarbGoal').textContent=g.carbs;
+  document.getElementById('nutrFatGoal').textContent=g.fat;
+
+  document.getElementById('nutrSummary').innerHTML=`
+    <div class="nutr-cal-row">
+      <div><div class="nutr-cal-num">${Math.round(totals.cal)}</div><div style="font-size:11px;color:var(--muted);letter-spacing:0.06em;text-transform:uppercase">kcal idag</div></div>
+      <div style="text-align:right"><div style="font-size:13px;font-weight:700;color:var(--text)">${g.calories-Math.round(totals.cal)}</div><div style="font-size:11px;color:var(--muted)">kcal kvar</div></div>
+    </div>
+    ${[['Protein','#E85D26',totals.prot,g.protein,'g'],['Kolhydrater','#2A6AE8',totals.carbs,g.carbs,'g'],['Fett','#22A647',totals.fat,g.fat,'g']].map(([n,c,v,max])=>`
+    <div class="rm-row" style="margin-bottom:10px">
+      <div class="rm-label"><span class="rm-name">${n}</span><span class="rm-val">${v} / ${max}${''}</span></div>
+      <div class="rm-bar"><div class="rm-fill" style="background:${c};width:${pctW(v,max)}"></div></div>
+    </div>`).join('')}`;
+
+  const MEAL_IDS=[['breakfast','Frukost'],['lunch','Lunch'],['dinner','Middag'],['snack','Mellanmål']];
+  document.getElementById('mealCards').innerHTML=MEAL_IDS.map(([id,label])=>{
+    const items=log.filter(e=>e.meal===id);
+    const mCal=items.reduce((s,e)=>s+e.cal,0);
+    return`<div class="meal-card">
+      <div class="meal-header">
+        <span class="meal-name">${label}</span>
+        <div style="display:flex;align-items:center;gap:10px">
+          <span class="meal-cal">${mCal?Math.round(mCal)+' kcal':''}</span>
+          <button class="meal-add" onclick="openAddFood('${id}')">+ Lägg till</button>
+        </div>
+      </div>
+      ${items.length?items.map(e=>`
+        <div class="food-item">
+          <div style="flex:1">
+            <div class="food-item-name">${e.foodName}</div>
+            <div class="food-item-detail">${e.amountG}g · ${Math.round(e.cal)} kcal</div>
+          </div>
+          <div class="food-item-macros">P${e.prot}·K${e.carbs}·F${e.fat}</div>
+          <button class="food-item-del" onclick="removeFoodEntry('${e.id}')">✕</button>
+        </div>`).join('')
+      :`<div class="meal-empty">Inga livsmedel tillagda</div>`}
+    </div>`;
+  }).join('');
+}
+
+function openAddFood(meal){
+  ST._addFoodMeal=meal;
+  ST._addFoodSelected=null;
+  const labels={breakfast:'Frukost',lunch:'Lunch',dinner:'Middag',snack:'Mellanmål'};
+  document.getElementById('modalTitle').textContent='Lägg till — '+labels[meal];
+  document.getElementById('modalBody').innerHTML=`
+    <input id="foodSearchInput" type="text" placeholder="Sök livsmedel..." oninput="renderFoodSearch(this.value)"
+      style="width:100%;padding:12px 14px;border:1.5px solid var(--border);border-radius:var(--radius-sm);font-size:15px;color:var(--text);background:var(--bg);outline:none;margin-bottom:4px">
+    <div id="foodSearchResults"></div>
+    <div id="foodAmountSection" style="display:none">
+      <div class="food-amount-section">
+        <div style="font-size:14px;font-weight:700;color:var(--text);margin-bottom:10px" id="foodSelectedName"></div>
+        <label style="font-size:12px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--muted)">Mängd (gram)</label>
+        <input id="foodAmountInput" type="number" value="100" min="1" max="2000"
+          style="width:100%;padding:12px;border:1.5px solid var(--border);border-radius:var(--radius-sm);font-size:20px;font-weight:700;color:var(--text);background:var(--card);text-align:center;margin-top:6px;outline:none"
+          oninput="updateFoodPreview()">
+        <div class="food-amount-preview" id="foodPreview"></div>
+      </div>
+      <button class="btn-primary" onclick="confirmAddFood()">Lägg till i logg</button>
+    </div>`;
+  renderFoodSearch('');
+  document.getElementById('modalOverlay').classList.add('show');
+  setTimeout(()=>document.getElementById('foodSearchInput')?.focus(),100);
+}
+
+function renderFoodSearch(q){
+  const lower=q.toLowerCase();
+  const results=FOODS.filter(f=>!q||f.name.toLowerCase().includes(lower)).slice(0,12);
+  document.getElementById('foodSearchResults').innerHTML=results.map(f=>`
+    <div class="food-search-item" onclick="selectFood('${f.id}')">
+      <div>
+        <div class="food-search-name">${f.name}</div>
+        <div class="food-search-meta">per 100g: ${f.cal} kcal · P${f.prot}g · K${f.carbs}g · F${f.fat}g</div>
+      </div>
+      <div style="font-size:18px;color:var(--muted)">›</div>
+    </div>`).join('')||'<div style="padding:20px;text-align:center;color:var(--muted)">Inga träffar</div>';
+}
+
+function selectFood(id){
+  ST._addFoodSelected=FOODS.find(f=>f.id===id);
+  document.getElementById('foodAmountSection').style.display='block';
+  document.getElementById('foodSelectedName').textContent=ST._addFoodSelected.name;
+  document.getElementById('foodSearchResults').style.display='none';
+  document.getElementById('foodSearchInput').style.display='none';
+  updateFoodPreview();
+}
+
+function updateFoodPreview(){
+  const f=ST._addFoodSelected;if(!f)return;
+  const g=parseFloat(document.getElementById('foodAmountInput').value)||100;
+  const m=foodMacros(f,g);
+  document.getElementById('foodPreview').innerHTML=`<b>${m.cal} kcal</b> &nbsp;·&nbsp; Protein ${m.prot}g &nbsp;·&nbsp; Kolhydrater ${m.carbs}g &nbsp;·&nbsp; Fett ${m.fat}g`;
+}
+
+async function confirmAddFood(){
+  const f=ST._addFoodSelected;if(!f)return;
+  const g=parseFloat(document.getElementById('foodAmountInput').value)||100;
+  const m=foodMacros(f,g);
+  const entry={id:'fl'+Date.now(),date:today(),meal:ST._addFoodMeal,foodId:f.id,foodName:f.name,amountG:g,cal:m.cal,prot:m.prot,carbs:m.carbs,fat:m.fat};
+  ST.foodLog.push(entry);
+  await save('fortis_foodlog',ST.foodLog);
+  document.getElementById('modalOverlay').classList.remove('show');
+  renderNutrition();
+}
+
+async function removeFoodEntry(id){
+  ST.foodLog=ST.foodLog.filter(e=>e.id!==id);
+  await save('fortis_foodlog',ST.foodLog);
+  renderNutrition();
+}
+
+// ── PROFILE ───────────────────────────────────────────────
+function renderProfile(){
+  const p=ST.profile;
+  if(!p)return;
+  const initials=(p.name||'?').split(' ').map(n=>n[0]).join('').toUpperCase().slice(0,2);
+  document.getElementById('profAvatar').textContent=initials;
+  document.getElementById('profName').textContent=p.name||'—';
+  const goals={lose:'Gå ner i vikt',maintain:'Hålla vikt',gain:'Bygga muskler'};
+  document.getElementById('profGoalText').textContent=`Mål: ${goals[p.goal]||'—'} · ${p.weight||'—'} kg`;
+  document.getElementById('psTotal').textContent=ST.workoutLog.length;
+  document.getElementById('psStreak').textContent=calcStreak();
+  document.getElementById('psWeight').textContent=p.weight||'—';
+  const unlocked=new Set(ST.achievements||[]);
+  document.getElementById('achGrid').innerHTML=ACHIEVEMENT_DEFS.map(a=>`
+    <div class="ach-card ${unlocked.has(a.id)?'':'locked'}">
+      <div class="ach-icon">${a.icon}</div>
+      <div><div class="ach-name">${a.name}</div><div class="ach-desc">${a.desc}</div></div>
+    </div>`).join('');
+  const g=ST.macroGoals;
+  const themeHTML=`
+    <div class="section-title" style="padding:0 0 10px;margin-top:20px">Tema</div>
+    <div class="theme-row">
+      ${Object.entries(THEMES).map(([id,t])=>`
+        <div style="flex:1">
+          <div class="theme-swatch ${ST.activeTheme===id?'active':''}" onclick="setTheme('${id}')">
+            <div class="theme-swatch-top" style="background:${t.bg}"></div>
+            <div class="theme-swatch-bot" style="background:${t.accent}"></div>
+            <div class="theme-swatch-check">✓</div>
+          </div>
+          <div class="theme-label">${t.name}</div>
+        </div>`).join('')}
+    </div>`;
+  document.getElementById('settingsItems').innerHTML=themeHTML+[
+    {label:'Kalorimål',val:g.calories+' kcal'},
+    {label:'Proteinmål',val:g.protein+'g'},
+    {label:'Längd',val:(p.height||'—')+'cm'},
+    {label:'Målvikt',val:(p.goalWeight||'—')+'kg'},
+    {label:'Vattenmål',val:ST.waterGoal+'ml'},
+  ].map(i=>`<div class="settings-item"><span class="si-label">${i.label}</span><span class="si-val">${i.val}</span></div>`).join('');
+}
+
+// ── ACTIVE WORKOUT ────────────────────────────────────────
+function startWorkout(wid){
+  const w=ST.workouts.find(x=>x.id===wid);if(!w)return;
+  ST.activeWorkout={...w,setStates:w.exercises.map(e=>Array.from({length:e.sets},()=>({done:false,reps:e.reps||0,weight:e.weight||0,dur:e.durationSec||0})))};
+  ST.awStartTime=Date.now();
+  document.getElementById('awName').textContent=w.name;
+  document.getElementById('active-workout').style.display='flex';
+  ST.awTimerInterval=setInterval(()=>{
+    const s=Math.floor((Date.now()-ST.awStartTime)/1000);
+    document.getElementById('awTimer').textContent=`${String(Math.floor(s/60)).padStart(2,'0')}:${String(s%60).padStart(2,'0')}`;
+  },1000);
+  renderActiveWorkout();
+}
+
+function renderActiveWorkout(){
+  const aw=ST.activeWorkout;
+  document.getElementById('awBody').innerHTML=aw.exercises.map((e,ei)=>{
+    const ex=getExercises().find(x=>x.id===e.exerciseId);if(!ex)return'';
+    const isTimer=!!e.durationSec;
+    return`<div class="aw-ex-card">
+      <div class="aw-ex-name">${ex.icon} ${ex.name}</div>
+      <div class="aw-sets">
+        <div class="aw-set-row" style="opacity:0.5;font-size:11px;letter-spacing:0.06em;margin-bottom:2px">
+          <div></div><div style="text-align:center;color:#666">${isTimer?'Sek':'Reps'}</div>
+          <div style="text-align:center;color:#666">${isTimer?'':' Kg'}</div><div></div>
+        </div>
+        ${aw.setStates[ei].map((set,si)=>`
+        <div class="aw-set-row">
+          <div class="set-num">${si+1}</div>
+          <input class="set-input" type="number" value="${isTimer?set.dur:set.reps}" min="0" onchange="updateSet(${ei},${si},'${isTimer?'dur':'reps'}',this.value)">
+          ${isTimer?`<div style="text-align:center;color:#444;font-size:13px">sek</div>`:
+          `<input class="set-input" type="number" value="${set.weight}" step="0.5" min="0" onchange="updateSet(${ei},${si},'weight',this.value)">`}
+          <button class="set-done ${set.done?'completed':''}" onclick="toggleSet(${ei},${si})">✓</button>
+        </div>`).join('')}
+      </div>
+    </div>`;
+  }).join('');
+}
+
+function updateSet(ei,si,field,val){ST.activeWorkout.setStates[ei][si][field]=parseFloat(val)||0;}
+
+function toggleSet(ei,si){
+  const set=ST.activeWorkout.setStates[ei][si];
+  set.done=!set.done;
+  if(set.done){
+    const restSec=ST.activeWorkout.exercises[ei]?.restSec||60;
+    startRest(restSec);
+  }
+  renderActiveWorkout();
+}
+
+function startRest(secs){
+  let t=secs;
+  document.getElementById('restNum').textContent=t;
+  document.getElementById('restOverlay').classList.add('show');
+  clearInterval(ST.restInterval);
+  ST.restInterval=setInterval(()=>{
+    t--;document.getElementById('restNum').textContent=t;
+    if(t<=0){clearInterval(ST.restInterval);document.getElementById('restOverlay').classList.remove('show');}
+  },1000);
+}
+
+function skipRest(){clearInterval(ST.restInterval);document.getElementById('restOverlay').classList.remove('show');}
+
+async function finishWorkout(){
+  clearInterval(ST.awTimerInterval);
+  const dur=Math.floor((Date.now()-ST.awStartTime)/1000/60);
+  const entry={id:Date.now(),date:today(),workoutId:ST.activeWorkout.id,workoutName:ST.activeWorkout.name,durationMin:dur,exercises:ST.activeWorkout.setStates};
+  ST.workoutLog.unshift(entry);
+  await save('fortis_workoutlog',ST.workoutLog);
+  document.getElementById('active-workout').style.display='none';
+  document.getElementById('streakCount').textContent=calcStreak();
+  document.getElementById('psTotal').textContent=ST.workoutLog.length;
+  document.getElementById('psStreak').textContent=calcStreak();
+  renderTodayWorkout();
+  alert(`Pass klart! 💪 Varade ${dur} minuter.`);
+  checkAchievements();
+}
+
+function closeWorkout(){
+  if(confirm('Avsluta passet utan att spara?')){
+    clearInterval(ST.awTimerInterval);clearInterval(ST.restInterval);
+    document.getElementById('active-workout').style.display='none';
+    document.getElementById('restOverlay').classList.remove('show');
+  }
+}
+
+// ── MODAL ─────────────────────────────────────────────────
+function closeModal(e){if(!e||e.target===document.getElementById('modalOverlay'))document.getElementById('modalOverlay').classList.remove('show');}
+
+function toggleFilterModal(){
+  const overlay=document.getElementById('filterOverlay');
+  const muscles=['Alla','Bröst','Rygg','Ben','Axlar','Armar','Core','Helkropp','Kondition'];
+  const diffs=['Alla','Nybörjare','Medel','Avancerad'];
+  overlay.querySelector('#fmMuscles').innerHTML=muscles.map(m=>
+    `<div class="filter-chip ${ST.muscleFilter===m?'active':''}" onclick="setMuscleFilter('${m}')">${m}</div>`
+  ).join('');
+  overlay.querySelector('#fmDiffs').innerHTML=diffs.map(d=>
+    `<div class="filter-chip ${ST.diffFilter===d?'active':''}" onclick="setDiffFilter('${d}')">${d}</div>`
+  ).join('');
+  overlay.classList.add('show');
+}
+
+function setMuscleFilter(m){
+  ST.muscleFilter=m;
+  document.querySelectorAll('#fmMuscles .filter-chip').forEach(c=>c.classList.toggle('active',c.textContent===m));
+}
+
+function setDiffFilter(d){
+  ST.diffFilter=d;
+  document.querySelectorAll('#fmDiffs .filter-chip').forEach(c=>c.classList.toggle('active',c.textContent===d));
+}
+
+function applyFilters(){
+  document.getElementById('filterOverlay').classList.remove('show');
+  updateFilterBadge();
+  filterExercises();
+}
+
+function resetFilters(){
+  ST.muscleFilter='Alla';
+  ST.diffFilter='Alla';
+  document.querySelectorAll('#fmMuscles .filter-chip').forEach(c=>c.classList.toggle('active',c.textContent==='Alla'));
+  document.querySelectorAll('#fmDiffs .filter-chip').forEach(c=>c.classList.toggle('active',c.textContent==='Alla'));
+}
+
+function closeFilterOverlay(e){
+  if(e.target===document.getElementById('filterOverlay'))applyFilters();
+}
+
+// ── CUSTOM EXERCISES ──────────────────────────────────────
+function openCreateExercise(){
+  ST._createExInstructions=[''];
+  document.getElementById('ceName').value='';
+  document.getElementById('ceIcon').value='';
+  document.getElementById('ceSecondary').value='';
+  renderCEInstructions();
+  document.getElementById('createExOverlay').classList.add('show');
+}
+function closeCreateExercise(e){
+  if(!e||e.target===document.getElementById('createExOverlay'))
+    document.getElementById('createExOverlay').classList.remove('show');
+}
+function renderCEInstructions(){
+  document.getElementById('ceInstructions').innerHTML=ST._createExInstructions.map((s,i)=>`
+    <div class="ce-instruction-row">
+      <input type="text" value="${s.replace(/"/g,'&quot;')}" placeholder="Steg ${i+1}..." oninput="ST._createExInstructions[${i}]=this.value">
+      <button onclick="removeInstruction(${i})">✕</button>
+    </div>`).join('');
+}
+function addInstruction(){
+  ST._createExInstructions.push('');
+  renderCEInstructions();
+}
+function removeInstruction(i){
+  ST._createExInstructions.splice(i,1);
+  if(!ST._createExInstructions.length)ST._createExInstructions=[''];
+  renderCEInstructions();
+}
+async function saveCustomExercise(){
+  const name=document.getElementById('ceName').value.trim();
+  if(!name){alert('Ange ett namn.');return;}
+  const icon=document.getElementById('ceIcon').value.trim()||'⚡';
+  const muscle=document.getElementById('ceMuscle').value;
+  const secondary=document.getElementById('ceSecondary').value.trim();
+  const equip=document.getElementById('ceEquip').value;
+  const diff=document.getElementById('ceDiff').value;
+  const type=document.getElementById('ceType').value;
+  const instructions=ST._createExInstructions.filter(s=>s.trim());
+  const ex={id:'custom_'+Date.now(),name,muscle,secondary,equip,icon,diff,type,instructions,isCustom:true};
+  ST.customExercises.push(ex);
+  await save('fortis_custom_exercises',ST.customExercises);
+  closeCreateExercise();
+  renderLibrary();
+}
+async function deleteCustomExercise(id){
+  if(!confirm('Ta bort övningen? Den försvinner från biblioteket.'))return;
+  ST.customExercises=ST.customExercises.filter(e=>e.id!==id);
+  await save('fortis_custom_exercises',ST.customExercises);
+  closeModal();
+  renderLibrary();
+}
+
+// ── RESET ─────────────────────────────────────────────────
+async function resetApp(){
+  if(!confirm('Återställ all data? Detta kan inte ångras.'))return;
+  if(window.storage){
+    try{await window.storage.delete('fortis_profile');}catch{}
+    try{await window.storage.delete('fortis_workouts');}catch{}
+    try{await window.storage.delete('fortis_workoutlog');}catch{}
+    try{await window.storage.delete('fortis_water_'+today());}catch{}
+  }
+  location.reload();
+}
+
+// ── START ─────────────────────────────────────────────────
+init();
+</script>
+</div>
+</body>
+</html>
diff --git a/FORTIS_HANDOFF.md b/FORTIS_HANDOFF.md
new file mode 100644
index 0000000..00a900a
--- /dev/null
+++ b/FORTIS_HANDOFF.md
@@ -0,0 +1,380 @@
+# FORTIS Träningsapp — Claude Code Handoff
+
+## Projektöversikt
+
+**Appnamn:** FORTIS
+**Stack:** React Native + Expo (målplattform) — prototyp byggd i HTML/JS
+**Nuvarande fas:** Fas 1 klar som HTML-prototyp, redo att migreras till React Native/Expo
+**Designriktning:** Mörk header / ljus content, accent #E85D26 (orange), minimalistisk men varm
+
+---
+
+## Vad som är byggt (Fas 1 — HTML-prototyp)
+
+Filen `FORTIS-app.html` innehåller en fullt fungerande prototyp med:
+
+- **Splash screen** — 3 sek animerad intro (roterande SVG-ring + progress-bar) → auto-redirect
+- **Onboarding** — 5-stegs wizard: välkommen → profil → mål → kalori/makroberäkning → klart
+  - Mifflin-St Jeor-formeln för TDEE-beräkning
+  - Sparar till storage efter steg 5
+- **Dashboard (Hem)** — SVG-kaloriering, makro-bars (P/K/F), vattendroppar, dagens pass, streak
+- **Schema** — veckostrip måndag–söndag, pass per dag, start av pass, lägg till nytt pass
+- **Aktiv träning** — sets/reps/vikt per set, ✓-knappar, 60 sek vilotimer, passtimer, spara till logg
+- **Övningsbibliotek** — 20 övningar, chip-filter på utrustning, fritextsök, detaljvy
+- **Kostlogg** — grundlayout med måltidssektion och makrospårning (ej fullständig)
+- **Profil** — profildata, stats, inställningar, reset
+
+---
+
+## Navigationstruktur
+
+Bottom nav med 5 flikar:
+```
+[ 🏠 Hem ] [ 📅 Schema ] [ 📚 Bibliotek ] [ 🍎 Kost ] [ 👤 Profil ]
+```
+
+---
+
+## Designbeslut (dokumenterade)
+
+### Färger
+```
+Accent:     #E85D26  (orange — CTA, aktiva element)
+Accent2:    #2A6AE8  (blå — kolhydrater, sekundär)
+Grön:       #22A647  (fett, success)
+Bakgrund:   #F2F1ED  (varm off-white)
+Kort:       #FFFFFF
+Text:       #141414
+Muted:      #888880
+Border:     rgba(0,0,0,0.09)
+Dark header:#0F0F0F  (splash, aktiv träning)
+```
+
+### Filter-UX i biblioteket (beslutad best practice)
+- **Utrustning** → horisontellt scrollbara toggle-chips (alltid synliga)
+- **Muskelgrupp + Svårighet** → filtermodal via ikon med badge-räknare
+- Filter kombineras (Ben + Kettlebell = båda måste matcha)
+
+### Utrustningskategorier
+Kroppsvikt, Hantel, Kettlebell, Skivstång, Kabelmaskin, Maskin, Motståndsband, TRX, Löpband, Medicinboll
+
+### Muskelgruppskategorier
+Bröst, Rygg, Axlar, Armar, Ben, Core, Kondition, Helkropp, Stretching
+
+---
+
+## Datamodeller (TypeScript-ready)
+
+```typescript
+interface Profile {
+  id: string
+  name: string
+  gender: 'male' | 'female' | 'other'
+  age: number
+  heightCm: number
+  weightKg: number
+  goalWeightKg: number
+  goal: 'lose' | 'maintain' | 'gain'
+  activityLevel: 'sedentary' | 'light' | 'moderate' | 'very_active'
+  macroGoals: MacroGoals
+  createdAt: string
+  updatedAt: string
+}
+
+interface MacroGoals {
+  calories: number
+  proteinG: number
+  carbsG: number
+  fatG: number
+}
+
+interface Exercise {
+  id: string
+  name: string
+  category: string
+  muscleGroups: string[]
+  secondaryMuscles: string[]
+  equipment: string[]
+  difficulty: 'beginner' | 'intermediate' | 'advanced'
+  type: 'strength' | 'cardio' | 'flexibility'
+  instructions: string[]
+  gifUrl?: string
+  wgerId?: number        // wger.de exercise ID — för GIF/video-hämtning via API i Fas 2
+  isCustom: boolean
+}
+
+interface WorkoutSchedule {
+  id: string
+  name: string
+  dayOfWeek?: number        // 0=mån, 6=sön
+  repeatEveryXDays?: number
+  exercises: ScheduledExercise[]
+  estimatedMinutes: number
+  muscleGroups: string[]
+  createdAt: string
+}
+
+interface ScheduledExercise {
+  exerciseId: string
+  sets: number
+  reps?: number
+  durationSeconds?: number
+  targetWeightKg?: number
+  restSeconds: number
+  notes?: string
+}
+
+interface WorkoutLogEntry {
+  id: string
+  scheduleId?: string
+  date: string              // ISO YYYY-MM-DD
+  startedAt: string
+  endedAt?: string
+  durationMinutes: number
+  exercises: LoggedExercise[]
+  notes?: string
+  completedManually: boolean
+}
+
+interface LoggedExercise {
+  exerciseId: string
+  sets: LoggedSet[]
+}
+
+interface LoggedSet {
+  reps?: number
+  weightKg?: number
+  durationSeconds?: number
+  completed: boolean
+}
+
+interface FoodLogEntry {
+  id: string
+  date: string
+  meal: 'breakfast' | 'lunch' | 'dinner' | 'snack'
+  foodId: string
+  foodName: string
+  amountG: number
+  calories: number
+  proteinG: number
+  carbsG: number
+  fatG: number
+  barcode?: string
+}
+
+interface MeasurementEntry {
+  id: string
+  date: string
+  weightKg?: number
+  waistCm?: number
+  bodyFatPct?: number
+  notes?: string
+}
+
+interface WaterLogEntry {
+  id: string
+  date: string
+  totalMl: number
+  entries: { time: string; ml: number }[]
+}
+```
+
+---
+
+## Lagringsnycklar
+
+```
+fortis_profile           → Profile
+fortis_macrogoals        → MacroGoals
+fortis_workouts          → WorkoutSchedule[]
+fortis_workoutlog        → WorkoutLogEntry[]
+fortis_water_YYYY-MM-DD  → number (ml)
+fortis_measurements      → MeasurementEntry[]
+fortis_foodlog           → FoodLogEntry[]
+fortis_custom_foods      → FoodItem[]
+fortis_achievements      → string[]
+```
+
+**Persistens-strategi:** Designad för direkt mappning mot `AsyncStorage` (React Native) eller `Expo SQLite`. Exportera all data som en JSON-fil via Profil → Inställningar → Exportera.
+
+---
+
+## Komponentstruktur (React Native / Expo)
+
+```
+src/
+├── app/                        # Expo Router (file-based routing)
+│   ├── _layout.tsx             # Root layout + bottom tabs
+│   ├── (tabs)/
+│   │   ├── index.tsx           # Dashboard / Hem
+│   │   ├── schedule.tsx        # Träningsschema
+│   │   ├── library.tsx         # Övningsbibliotek
+│   │   ├── nutrition.tsx       # Kostlogg
+│   │   └── profile.tsx         # Profil & inställningar
+│   ├── onboarding/
+│   │   └── index.tsx           # Onboarding-wizard
+│   └── workout/
+│       └── [id].tsx            # Aktiv träningsvy
+│
+├── components/
+│   ├── shared/
+│   │   ├── ProgressRing.tsx    # SVG-kaloriering
+│   │   ├── MacroBar.tsx        # P/K/F progress-bar
+│   │   ├── WorkoutTimer.tsx    # Passtimer
+│   │   ├── RestTimer.tsx       # Vilotimer-overlay
+│   │   ├── ProgressionChart.tsx# Linjediagram per övning
+│   │   ├── StreakBadge.tsx     # Streak-display
+│   │   └── EquipChip.tsx      # Utrustningsfilter-chip
+│   ├── home/
+│   │   ├── CalorieCard.tsx
+│   │   ├── WaterTracker.tsx
+│   │   └── TodayWorkoutCard.tsx
+│   ├── schedule/
+│   │   ├── WeekStrip.tsx
+│   │   ├── WorkoutBlock.tsx
+│   │   └── AddWorkoutModal.tsx
+│   ├── library/
+│   │   ├── ExerciseCard.tsx
+│   │   ├── ExerciseDetailModal.tsx
+│   │   └── FilterModal.tsx
+│   ├── nutrition/
+│   │   ├── MealSection.tsx
+│   │   ├── AddFoodModal.tsx
+│   │   ├── BarcodeScanner.tsx  # Expo Camera
+│   │   └── MacroSummary.tsx
+│   └── profile/
+│       ├── WeightChart.tsx
+│       └── Achievements.tsx
+│
+├── store/
+│   ├── useProfileStore.ts      # Zustand store
+│   ├── useWorkoutStore.ts
+│   ├── useNutritionStore.ts
+│   └── useMeasurementStore.ts
+│
+├── lib/
+│   ├── storage.ts              # AsyncStorage wrapper
+│   ├── macroCalc.ts            # Mifflin-St Jeor
+│   ├── exportData.ts           # JSON-export
+│   └── exerciseData.ts         # Alla 20+ övningar (utbyggbar)
+│
+└── constants/
+    ├── colors.ts
+    ├── exercises.ts
+    └── theme.ts
+```
+
+### Tema-modulens ansvar (frikopplad från appen)
+
+Temat ska vara en **självständig modul** — appen konsumerar det, äger det inte.
+
+```
+src/constants/theme.ts        ← THEMES-objekt + typdefinitioner
+src/store/useThemeStore.ts    ← Zustand: activeTheme, setTheme(), persist
+src/hooks/useTheme.ts         ← hook: returnerar aktiva CSS-värden
+```
+
+**Regler:**
+- Inga färgvärden hårdkodas i komponenter — alltid via `useTheme()`
+- `setTheme()` i store sköter persist (`AsyncStorage key: fortis_theme`)
+- Nya teman läggs **enbart** till i `theme.ts` — inga ändringar i komponenter
+- `_layout.tsx` applicerar temat på root-nivå via `ThemeProvider`
+
+**Nuvarande teman (från HTML-prototypen):**
+`fortis` · `dark` · `midnight` · `forest` · `stone`
+
+---
+
+## Fas-plan
+
+| Fas | Innehåll | Status |
+|-----|----------|--------|
+| **Fas 1** | Splash, Onboarding, Dashboard, Schema, Aktiv träning, Bibliotek (grund) | ✅ Klar (HTML-prototyp) |
+| **Fas 2** | Progressionsgraf per övning, Achievements/streaks, Utbyggt bibliotek (GIFs) | 🔄 Pågår |
+| **Fas 3** | Fullständig kostlogg, Makrospårning, Matdatabas-sökning, Vattenlogg | 🔜 |
+| **Fas 4** | Barcodeläsare, Open Food Facts API, Notifikationer, Invägningsdag | 🔜 |
+| **Fas 5** | React Native-migration, offline-stöd, push-notiser, App Store | 🔜 |
+
+---
+
+## Tech Stack (produktion)
+
+| Komponent | Val |
+|-----------|-----|
+| Framework | React Native + Expo SDK 51+ |
+| Routing | Expo Router (file-based) |
+| State | Zustand |
+| Persistens | AsyncStorage + Expo SQLite |
+| Charts | Victory Native |
+| Animationer | React Native Reanimated 3 |
+| Barcode | Expo Camera + expo-barcode-scanner |
+| Matdatabas | Open Food Facts API (https://world.openfoodfacts.org/api/v0/product/{barcode}.json) |
+| Icons | Expo Vector Icons / Lucide RN |
+| Notiser | Expo Notifications |
+
+---
+
+## Övnings-dataset (nuvarande 20 st)
+
+```typescript
+// Finns i HTML-prototypen, extrahera till src/constants/exercises.ts
+// Struktur per övning:
+{
+  id: 'pushup',
+  name: 'Armhävningar',
+  muscle: 'Bröst',          // primär
+  secondary: 'Triceps, Axlar',
+  equip: 'Kroppsvikt',
+  icon: '💪',
+  diff: 'Nybörjare',
+  type: 'Styrka',
+  isTimer: false,            // true = tidsbaserad (plank etc.)
+  instructions: string[]
+}
+```
+
+Utöka till minst 100 övningar i Fas 2. Strukturen är exportklar.
+
+---
+
+## Export-format (JSON)
+
+```json
+{
+  "exportVersion": "1.0",
+  "exportedAt": "ISO-timestamp",
+  "profile": { },
+  "workoutSchedules": [ ],
+  "workoutLog": [ ],
+  "foodLog": [ ],
+  "measurements": [ ],
+  "waterLog": [ ],
+  "customFoods": [ ]
+}
+```
+
+---
+
+## Känd teknisk skuld / TODO
+
+- [x] Filtermodal (muskelgrupp + svårighet) — implementerad i prototypen
+- [x] Övningsdatabas utökad till 75 övningar (från wger.de)
+- [ ] Migrera tema-system till frikopplad modul (`theme.ts` + `useThemeStore.ts` + `useTheme()`) — inga färger hårdkodas i komponenter
+- [ ] Lägg till `wgerId` på alla 75 övningar i `exerciseData.ts` vid RN-migration — möjliggör GIF/video-hämtning via `GET https://wger.de/api/v2/exerciseinfo/{wgerId}/`
+- [x] Användardefinierade övningar — formulär i biblioteket, `isCustom: true`, persist i `fortis_custom_exercises`, EGEN-badge + radering
+- [x] Kostlogg — 30 livsmedel, sök-modal per måltid, gram-input, live makrobars + kaloriräknare, persist i `fortis_foodlog`
+- [ ] Barcodeläsare är stub — kräver Expo Camera i RN
+- [x] Progressionsgraf — SVG-linjediagram per övning, PR-markering, stats (PR/pass/senast), nås via "Se progression" i övningsdetaljvyn
+- [x] Vilotimerns längd — använder nu `restSec` från övningskonfigurationen (fallback 60s)
+- [ ] Inga notifikationer ännu
+- [x] Onboarding kan hoppas över — "Hoppa över" på steg 1, skapar profil med defaults direkt
+
+---
+
+## Starta prototypen
+
+Öppna `FORTIS-app.html` direkt i webbläsaren. All data sparas i `window.storage` (Claude artifact API) — byt mot `AsyncStorage` i RN.
+
+---
+
+*Handoff skapad: 2026-04-29*
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..99e17ee
--- /dev/null
+++ b/README.md
@@ -0,0 +1,558 @@
+# FORTIS — Tränings- och hälsoapp
+
+> Personlig träningsapp med fokus på progressionsspårning, kostlogg och schemaläggning.
+> Prototyp byggd i HTML/JS — målplattform React Native + Expo.
+
+---
+
+## Innehåll
+
+- [Kom igång](#kom-igång)
+- [Funktioner](#funktioner)
+- [Skärmar](#skärmar)
+- [Övningsbibliotek](#övningsbibliotek)
+- [Kostdatabas](#kostdatabas)
+- [Tema-system](#tema-system)
+- [Achievements](#achievements)
+- [Datalagring](#datalagring)
+- [Datamodeller](#datamodeller)
+- [Arkitektur (React Native)](#arkitektur-react-native)
+- [Roadmap](#roadmap)
+- [Tech stack](#tech-stack)
+
+---
+
+## Kom igång
+
+Prototypen är en enda HTML-fil — ingen installation krävs.
+
+```bash
+# Öppna direkt i webbläsaren
+open FORTIS-app.html
+```
+
+All data sparas i `window.storage` (Claude artifact API) under development.
+Vid React Native-migration byts detta mot `AsyncStorage` / `Expo SQLite`.
+
+---
+
+## Funktioner
+
+### Implementerat i HTML-prototypen
+
+| Funktion | Status | Detaljer |
+|---|---|---|
+| Splash screen | ✅ | 3 sek animerad SVG-ring + progress-bar → auto-redirect |
+| Onboarding | ✅ | 5-stegs wizard, Mifflin-St Jeor TDEE-beräkning, kan hoppas över |
+| Dashboard | ✅ | SVG-kaloriering, makrobars, vattenspårning, dagens pass, streak |
+| Träningsschema | ✅ | Veckostrip mån–sön, pass per dag, lägg till/ta bort |
+| Aktiv träning | ✅ | Sets/reps/vikt, vilotimer (per övning), passtimer, spara till logg |
+| Övningsbibliotek | ✅ | 75 övningar, utrustningschips, filtermodal (muskelgrupp + svårighet), sök |
+| Egna övningar | ✅ | Skapa/ta bort egna övningar, EGEN-badge, persist i `fortis_custom_exercises` |
+| Progressionsgraf | ✅ | SVG-linjediagram per övning, PR-markering, statistik |
+| Kostlogg | ✅ | 30 livsmedel, sök per måltid, gram-input, live makrobars |
+| Achievements | ✅ | 10 achievements, toast-notis vid upplåsning, grid i profil |
+| Tema-system | ✅ | 5 teman, väljs i Profil, persist i storage |
+| Profil & stats | ✅ | Profildata, pass totalt, streak, viktmål, inställningar |
+
+### Ej implementerat ännu (kräver React Native)
+
+| Funktion | Fas | Blockerat av |
+|---|---|---|
+| Barcodeläsare | 4 | Expo Camera |
+| Open Food Facts API | 4 | Native network + barcode |
+| Push-notifikationer | 4 | Expo Notifications |
+| Invägningsdag med påminnelse | 4 | Notifications |
+| Progressionsgraf med Victory Native | 5 | RN-migration |
+| Offline-stöd | 5 | RN-migration |
+
+---
+
+## Skärmar
+
+### 🏠 Hem (Dashboard)
+Daglig översikt på ett ögonkast:
+- **Kaloriering** — SVG-cirkel med kcal in / mål, dynamisk färgfyllning
+- **Makrobars** — Protein / Kolhydrater / Fett med procent-fill
+- **Vattenspårning** — visuella droppar, +2,5 dl snabbknapp, dagsmål 2 500 ml
+- **Dagens pass** — namn, antal övningar, snabbstart-knapp
+- **Streak-pill** — antal dagar i rad med loggat pass
+
+### 📅 Schema
+- Veckostrip måndag–söndag, aktiv dag markerad
+- Pass per dag med övningslista
+- Lägg till nytt pass (namn + dag)
+- Starta pass direkt → aktiv träningsvy
+
+#### Aktiv träning (modal)
+- Varje övning med sets × reps × vikt, editerbara live
+- ✓-knapp per set → startar vilotimer (tid konfigurerad per övning)
+- Passtimer (MM:SS) i headern
+- Avsluta → sparar till träningslogg
+
+### 📚 Övningsbibliotek
+**Filtreringssystem — hybrid-UX:**
+- *Nivå 1:* Horisontellt scrollbara utrustningschips (alltid synliga)
+- *Nivå 2:* Filtermodal via Filter-knapp — muskelgrupp + svårighet
+- Fritextsök i realtid
+- Badge på filterknappen visar antal aktiva filter
+
+**Övningskort visar:** namn, primär muskelgrupp, utrustning, svårighet
+**Detaljvy:** steg-för-steg instruktioner, sekundära muskler
+**Progressionsvy:** SVG-linjediagram, PR-markering, stats (PR / antal pass / senast loggat)
+
+### 🍎 Kost
+- **Summarykortet** — kcal loggat / kvar, live makrobars
+- **Måltidssektioner:** Frukost / Lunch / Middag / Mellanmål
+- "+ Lägg till" per måltid → sök-modal med 30 livsmedel
+- Välj livsmedel → ange gram → bekräfta → makron beräknas automatiskt
+- ✕ på loggad post tar bort direkt, makrona uppdateras
+
+### 👤 Profil
+- Avatar med initialer, namn, mål + aktuell vikt
+- Stats: pass totalt · streak · vikt
+- **Achievements-grid** — 10 achievements, låsta 38% opacity
+- **Tema-väljare** — 5 färgswatches
+- Inställningar: kalorimål, protein, längd, målvikt, vattenmål
+- Återställ app (rensar all data)
+
+---
+
+## Övningsbibliotek
+
+75 övningar hämtade från [wger.de](https://wger.de) + egna (engelska namn, kan översättas).
+
+### Fördelning per muskelgrupp
+
+| Muskelgrupp | Antal |
+|---|---|
+| Ben | 18 |
+| Rygg | 11 |
+| Core | 11 |
+| Bröst | 10 |
+| Armar | 9 |
+| Axlar | 8 |
+| Kondition | 7 |
+| Helkropp | 1 |
+
+### Fördelning per utrustning
+
+| Utrustning | Antal |
+|---|---|
+| Kroppsvikt | 33 |
+| Hantel | 19 |
+| Skivstång | 7 |
+| Maskin | 6 |
+| Kabelmaskin | 5 |
+| Kettlebell | 3 |
+| Motståndsband | 1 |
+| Löpband | 1 |
+
+### Utöka biblioteket
+Varje övning följer detta schema:
+```javascript
+{
+  id: 'exercise_id',
+  name: 'Exercise Name',
+  muscle: 'Ben',           // primär muskelgrupp
+  secondary: 'Rumpa, Core', // sekundära (sträng)
+  equip: 'Kroppsvikt',     // måste matcha EQUIP_CHIPS
+  icon: '🦵',
+  diff: 'Nybörjare',       // Nybörjare | Medel | Avancerad
+  type: 'Styrka',          // Styrka | Kondition | Stretching
+  isTimer: false,          // true = tidsbaserad (plank, löpband etc.)
+  instructions: ['Steg 1', 'Steg 2', ...]
+}
+```
+
+**wger.de API** kan användas för att hämta fler övningar:
+```
+GET https://wger.de/api/v2/exerciseinfo/{id}/?format=json
+```
+Lägg till `wgerId` på övningen för att koppla mot wger och hämta GIF/video i Fas 2.
+
+### Egna övningar
+
+Användaren kan skapa egna övningar direkt i biblioteket via **"+ Ny övning"**-knappen.
+
+- Fält: namn, emoji-ikon, muskelgrupp, sekundära muskler, utrustning, svårighet, typ, instruktioner (dynamiska steg)
+- Sparas till `fortis_custom_exercises` i storage med `isCustom: true`
+- Visas med orange **EIGEN**-badge och accentbård i listan
+- Detaljvyn visar 🗑 Ta bort-knapp (enbart för egna)
+- Fungerar fullt ut med aktiv träning, progression och schemaläggning
+
+---
+
+## Kostdatabas
+
+30 vanliga livsmedel, alla med makrovärden per 100g.
+
+| Kategori | Livsmedel |
+|---|---|
+| Kött & fisk | Kycklingfilé, Nötfärs, Lax, Tonfisk, Ägg, Räkor |
+| Mejeri | Mjölk, Grekisk yoghurt, Keso, Ost, Kvarg |
+| Spannmål | Havregryn, Ris, Pasta, Vitt bröd, Rågbröd, Tortilla |
+| Grönsaker | Broccoli, Spenat, Potatis, Sötpotatis |
+| Frukt | Banan, Äpple, Blåbär |
+| Nötter & övrigt | Mandlar, Jordnötssmör, Olivolja, Avokado, Proteinpulver, Kidneybönor |
+
+**Utöka databasen** — lägg till objekt i `FOODS`-arrayen:
+```javascript
+{id: 'mitt_livsmedel', name: 'Mitt Livsmedel', cal: 200, prot: 15, carbs: 20, fat: 5}
+```
+
+I Fas 4 ersätts/kompletteras detta med [Open Food Facts API](https://world.openfoodfacts.org/api/v0/product/{barcode}.json) via barcodeläsare.
+
+---
+
+## Tema-system
+
+5 inbyggda teman, väljs i Profil-fliken. Alla CSS-variabler byts atomärt.
+
+| Tema | Bakgrund | Accent | Karaktär |
+|---|---|---|---|
+| **Fortis** | Varm off-white `#F2F1ED` | Orange `#E85D26` | Standard, varm |
+| **Dark** | Kol `#121212` | Orange `#E85D26` | Mörkt läge |
+| **Midnight** | Navy `#0D1117` | Blå `#5B8BFF` | GitHub-mörkt |
+| **Forest** | Naturgrön `#F0F4F0` | Grön `#2D9E5F` | Lugnt, naturligt |
+| **Stone** | Cool grå `#F5F5F4` | Indigo `#6366F1` | Modernt, minimalt |
+
+### CSS-variabler
+```css
+--accent        /* CTA, aktiva element */
+--accent2       /* Sekundär accent, kolhydrater */
+--accent-light  /* Tint av accent för bakgrunder */
+--bg            /* Sidans bakgrund */
+--card          /* Kortbakgrund */
+--text          /* Primär text */
+--muted         /* Sekundär text, labels */
+--border        /* Kortlinjer, separatorer */
+--nav           /* Bottom navigation */
+--header        /* Mörk header (hem, bibliotek etc.) */
+--header-text   /* Text i mörk header */
+--outer         /* Bakgrund utanför app-ramen */
+```
+
+### React Native-migration
+Temat ska vara en **frikopplad modul** — appen konsumerar, äger inte:
+```
+src/constants/theme.ts     ← THEMES-objekt + typdefinitioner
+src/store/useThemeStore.ts ← Zustand: activeTheme, setTheme(), persist
+src/hooks/useTheme.ts      ← hook: returnerar aktiva värden
+```
+Inga färgvärden hårdkodas i komponenter. Nya teman läggs bara till i `theme.ts`.
+
+---
+
+## Achievements
+
+10 achievements som låses upp automatiskt efter avslutat pass.
+
+| Achievement | Ikon | Villkor |
+|---|---|---|
+| Första passet | 🏋️ | Slutför 1 pass |
+| 10 pass | 💪 | Slutför 10 pass totalt |
+| 50 pass | 🏆 | Slutför 50 pass totalt |
+| 100 pass | 🥇 | Slutför 100 pass totalt |
+| 3 i rad | 🔥 | 3 dagars träningsstreak |
+| Vecka på raken | 🔥 | 7 dagars träningsstreak |
+| Månadsstreak | 🔥 | 30 dagars träningsstreak |
+| Tidig fågel | 🌅 | Logga ett pass före 08:00 |
+| Allrounder | 🌟 | Träna 5 olika muskelgrupper |
+| Uthållighet | ⏱️ | Slutför ett pass längre än 60 min |
+
+Toast-notis slidar in uppifrån vid upplåsning. Visas som grid i Profil med låsta achievements i 38% opacity.
+
+---
+
+## Datalagring
+
+### Storage-nycklar
+
+| Nyckel | Typ | Innehåll |
+|---|---|---|
+| `fortis_profile` | `Profile` | Profildata + makromål |
+| `fortis_macrogoals` | `MacroGoals` | Kalorier, protein, kolhydrater, fett |
+| `fortis_workouts` | `WorkoutSchedule[]` | Schemalagda pass |
+| `fortis_workoutlog` | `WorkoutLogEntry[]` | Loggade genomförda pass |
+| `fortis_foodlog` | `FoodLogEntry[]` | Loggad mat per dag |
+| `fortis_water_YYYY-MM-DD` | `number` | Vattenintag i ml per datum |
+| `fortis_measurements` | `MeasurementEntry[]` | Vikt, midjemått, fettprocent |
+| `fortis_achievements` | `string[]` | Upplåsta achievement-IDs |
+| `fortis_theme` | `string` | Aktivt tema-ID |
+| `fortis_custom_foods` | `FoodItem[]` | Användarens egna livsmedel |
+| `fortis_custom_exercises` | `Exercise[]` | Användarens egna övningar (`isCustom: true`) |
+
+### Export-format
+```json
+{
+  "exportVersion": "1.0",
+  "exportedAt": "2026-04-29T12:00:00Z",
+  "profile": {},
+  "workoutSchedules": [],
+  "workoutLog": [],
+  "foodLog": [],
+  "measurements": [],
+  "waterLog": [],
+  "customFoods": []
+}
+```
+Export triggas via Profil → Exportera data → JSON-fil.
+
+---
+
+## Datamodeller
+
+```typescript
+interface Profile {
+  id: string
+  name: string
+  gender: 'male' | 'female' | 'other'
+  age: number
+  heightCm: number
+  weightKg: number
+  goalWeightKg: number
+  goal: 'lose' | 'maintain' | 'gain'
+  activityLevel: 'sedentary' | 'light' | 'moderate' | 'very_active'
+  macroGoals: MacroGoals
+  createdAt: string
+  updatedAt: string
+}
+
+interface MacroGoals {
+  calories: number
+  proteinG: number
+  carbsG: number
+  fatG: number
+}
+
+interface Exercise {
+  id: string
+  name: string
+  category: string
+  muscleGroups: string[]
+  secondaryMuscles: string[]
+  equipment: string[]
+  difficulty: 'beginner' | 'intermediate' | 'advanced'
+  type: 'strength' | 'cardio' | 'flexibility'
+  instructions: string[]
+  gifUrl?: string
+  wgerId?: number       // kopplar till wger.de API för GIF/video
+  isCustom: boolean
+}
+
+interface WorkoutSchedule {
+  id: string
+  name: string
+  dayOfWeek?: number    // 0=mån … 6=sön
+  repeatEveryXDays?: number
+  exercises: ScheduledExercise[]
+  estimatedMinutes: number
+  muscleGroups: string[]
+  createdAt: string
+}
+
+interface ScheduledExercise {
+  exerciseId: string
+  sets: number
+  reps?: number
+  durationSeconds?: number
+  targetWeightKg?: number
+  restSeconds: number
+  notes?: string
+}
+
+interface WorkoutLogEntry {
+  id: string
+  scheduleId?: string
+  date: string          // ISO YYYY-MM-DD
+  startedAt: string
+  endedAt?: string
+  durationMinutes: number
+  exercises: LoggedExercise[]
+  notes?: string
+  completedManually: boolean
+}
+
+interface LoggedExercise {
+  exerciseId: string
+  sets: LoggedSet[]
+}
+
+interface LoggedSet {
+  reps?: number
+  weightKg?: number
+  durationSeconds?: number
+  completed: boolean
+}
+
+interface FoodLogEntry {
+  id: string
+  date: string
+  meal: 'breakfast' | 'lunch' | 'dinner' | 'snack'
+  foodId: string
+  foodName: string
+  amountG: number
+  calories: number
+  proteinG: number
+  carbsG: number
+  fatG: number
+  barcode?: string
+}
+
+interface FoodItem {
+  id: string
+  name: string
+  brand?: string
+  barcode?: string
+  per100g: { calories: number; proteinG: number; carbsG: number; fatG: number }
+  isCustom: boolean
+}
+
+interface MeasurementEntry {
+  id: string
+  date: string
+  weightKg?: number
+  waistCm?: number
+  bodyFatPct?: number
+  notes?: string
+}
+
+interface WaterLogEntry {
+  id: string
+  date: string
+  totalMl: number
+  entries: { time: string; ml: number }[]
+}
+```
+
+---
+
+## Arkitektur (React Native)
+
+```
+src/
+├── app/                         # Expo Router (file-based routing)
+│   ├── _layout.tsx              # Root layout + ThemeProvider + bottom tabs
+│   ├── (tabs)/
+│   │   ├── index.tsx            # Dashboard / Hem
+│   │   ├── schedule.tsx         # Träningsschema
+│   │   ├── library.tsx          # Övningsbibliotek
+│   │   ├── nutrition.tsx        # Kostlogg
+│   │   └── profile.tsx          # Profil & inställningar
+│   ├── onboarding/
+│   │   └── index.tsx            # Onboarding-wizard (5 steg)
+│   └── workout/
+│       └── [id].tsx             # Aktiv träningsvy
+│
+├── components/
+│   ├── shared/
+│   │   ├── ProgressRing.tsx     # SVG-kaloriering
+│   │   ├── MacroBar.tsx         # P/K/F progress-bar
+│   │   ├── WorkoutTimer.tsx     # Passtimer
+│   │   ├── RestTimer.tsx        # Vilotimer-overlay
+│   │   ├── ProgressionChart.tsx # Linjediagram (Victory Native)
+│   │   ├── StreakBadge.tsx      # Streak-display
+│   │   └── EquipChip.tsx        # Utrustningsfilter-chip
+│   ├── home/
+│   │   ├── CalorieCard.tsx
+│   │   ├── WaterTracker.tsx
+│   │   └── TodayWorkoutCard.tsx
+│   ├── schedule/
+│   │   ├── WeekStrip.tsx
+│   │   ├── WorkoutBlock.tsx
+│   │   └── AddWorkoutModal.tsx
+│   ├── library/
+│   │   ├── ExerciseCard.tsx
+│   │   ├── ExerciseDetailModal.tsx
+│   │   └── FilterModal.tsx
+│   ├── nutrition/
+│   │   ├── MealSection.tsx
+│   │   ├── AddFoodModal.tsx
+│   │   ├── BarcodeScanner.tsx   # Expo Camera
+│   │   └── MacroSummary.tsx
+│   └── profile/
+│       ├── WeightChart.tsx
+│       └── Achievements.tsx
+│
+├── store/                       # Zustand stores
+│   ├── useProfileStore.ts
+│   ├── useWorkoutStore.ts
+│   ├── useNutritionStore.ts
+│   ├── useMeasurementStore.ts
+│   └── useThemeStore.ts         # activeTheme, setTheme(), persist
+│
+├── hooks/
+│   └── useTheme.ts              # returnerar aktiva temavärden
+│
+├── lib/
+│   ├── storage.ts               # AsyncStorage wrapper
+│   ├── macroCalc.ts             # Mifflin-St Jeor TDEE
+│   ├── exportData.ts            # JSON-export
+│   └── exerciseData.ts          # 75+ övningar (utbyggbar)
+│
+└── constants/
+    ├── colors.ts
+    ├── exercises.ts
+    └── theme.ts                 # THEMES-objekt + typdefinitioner
+```
+
+---
+
+## Roadmap
+
+| Fas | Innehåll | Status |
+|---|---|---|
+| **Fas 1** | Splash, Onboarding, Dashboard, Schema, Aktiv träning, Bibliotek | ✅ Klar |
+| **Fas 2** | Progressionsgraf, Achievements/streaks, Utbyggt bibliotek | 🔄 Pågår |
+| **Fas 3** | Fullständig kostlogg, Makrospårning, Matdatabas, Vattenlogg | 🔄 Pågår |
+| **Fas 4** | Barcodeläsare, Open Food Facts API, Notifikationer, Invägningsdag | 🔜 |
+| **Fas 5** | React Native-migration, offline-stöd, push-notiser, App Store | 🔜 |
+
+### Närmast kvar
+- [ ] Barcodeläsare (Expo Camera) — ersätter sök-modal med skannad streckkod
+- [ ] Open Food Facts API-integration
+- [ ] Push-notifikationer (pass-påminnelse, vattenintag, invägningsdag)
+- [ ] Egna livsmedel — `isCustom: true`, persist i `fortis_custom_foods`
+- [x] Egna övningar — `isCustom: true`, persist i `fortis_custom_exercises`
+- [ ] `wgerId` på alla 75 övningar vid RN-migration (GIF/video via wger API)
+
+---
+
+## Tech stack
+
+| Komponent | Prototyp | Produktion (RN) |
+|---|---|---|
+| UI | HTML + CSS | React Native + Expo SDK 51+ |
+| Routing | Tab-state i JS | Expo Router (file-based) |
+| State | Globalt `ST`-objekt | Zustand |
+| Persistens | `window.storage` | AsyncStorage + Expo SQLite |
+| Charts | SVG (hand-built) | Victory Native |
+| Animationer | CSS transitions | React Native Reanimated 3 |
+| Barcode | — (stub) | Expo Camera + expo-barcode-scanner |
+| Matdatabas | 30 inbyggda livsmedel | Open Food Facts API |
+| Icons | Emoji | Expo Vector Icons / Lucide RN |
+| Notiser | — | Expo Notifications |
+
+### Kaloriformel
+TDEE beräknas med **Mifflin-St Jeor**:
+
+```
+Män:   BMR = 10×vikt + 6.25×längd − 5×ålder + 5
+Kvinnor: BMR = 10×vikt + 6.25×längd − 5×ålder − 161
+
+TDEE = BMR × aktivitetsmultiplikator
+  sedentary:   × 1.2
+  light:       × 1.375
+  moderate:    × 1.55
+  very_active: × 1.725
+
+Mål-justering:
+  lose:     TDEE − 500 kcal
+  maintain: TDEE
+  gain:     TDEE + 300 kcal
+```
+
+---
+
+*Senast uppdaterad: 2026-04-29*
diff --git a/Träningsapp_Planering.md b/Träningsapp_Planering.md
new file mode 100644
index 0000000..523543c
--- /dev/null
+++ b/Träningsapp_Planering.md
@@ -0,0 +1,510 @@
+# Träningsapp — Planeringsspecifikation
+**Version:** 1.1
+**Status:** Planeringsfas
+**Målplattform:** JSX (prototyp) → React Native / Expo (produktion)
+
+---
+
+## 1. Appöversikt
+
+En fullständig personlig tränings- och hälsoapp med fokus på progressionsspårning, kostlogg och schemaläggning. Designad med en exporterbar datamodell för smidig migrering till React Native.
+
+---
+
+## 2. Navigationstruktur
+
+**Bottom navigation — 5 flikar:**
+
+```
+[ 🏠 Hem ]  [ 📅 Schema ]  [ 📚 Bibliotek ]  [ 🍎 Kost ]  [ 👤 Profil ]
+```
+
+Övningsloggen nås via hemvyn och schemat (inte en egen flik).
+
+---
+
+## 3. Skärmar och funktioner
+
+### 3.1 Startskärm / Splash
+- Animerad välkomstbild (logo + rörlig bakgrund, t.ex. pulsande ring eller partikeleffekt)
+- Varaktighet: **3 sekunder**, sedan automatisk redirect
+- Om ny användare → Onboarding-flöde
+- Om återvändande användare → Dashboard
+
+---
+
+### 3.2 Onboarding-flöde
+Triggas automatiskt efter splash om ingen profil finns. **5 steg, kan hoppas över (fas 2-data fylls i senare).**
+
+**Steg 1 — Välkommen**
+- Appens namn + kort tagline
+- "Kom igång"-knapp
+
+**Steg 2 — Profil**
+- Namn
+- Kön (påverkar kaloriformel)
+- Ålder
+- Längd (cm)
+- Vikt (kg)
+
+**Steg 3 — Mål**
+- Målvikt (kg)
+- Mål: Gå ner / Hålla vikt / Bygga muskler
+- Aktivitetsnivå: Stillasittande / Lätt aktiv / Måttligt aktiv / Mycket aktiv
+
+**Steg 4 — Kalori- och makromål**
+- Auto-beräknat via Harris-Benedict / Mifflin-St Jeor
+- Visar: Kalorier / Protein / Kolhydrater / Fett
+- Kan justeras manuellt
+
+**Steg 5 — Klart**
+- Sammanfattningskort
+- "Starta appen"-knapp → Dashboard
+
+---
+
+### 3.3 Dashboard (Hemvy)
+**Daglig översikt på ett ögonkast.**
+
+- Hälsningsfras med namn och datum
+- **Dagens ringindikator:** Kalorier in / Kalorier ut (cirkulär progress)
+- **Dagens pass:** Nästa schemalagda pass med snabbstartknapp
+- **Makrospårning:** Protein / Kolhydrater / Fett (mini progress-bars)
+- **Vattenintag:** Snabblogg med + / - knappar (mål: 2–3 l)
+- **Streak-banner:** Antal dagar i rad, veckomål uppnått
+- **Senaste mätning:** Vikt + midjemått (om aktiverat)
+- **Snabblänkar:** Logga mat / Logga pass / Se progress
+
+---
+
+### 3.4 Övningsbibliotek
+
+**Sökning:**
+- Fritextsökning på övningsnamn
+- Sortering: A–Ö / Popularitet / Muskelgrupp
+
+**Filter-UX — hybridmodell (best practice):**
+
+*Nivå 1 — Horisontellt scrollbara utrustnings-chips (alltid synliga):*
+Kroppsvikt / Hantel / Kettlebell / Skivstång / Kabelmaskin / Maskin / Motståndsband / TRX / Löpband / Medicinboll
+
+Aktiv chip = fylld bakgrund. Direkt synliga eftersom utrustning är det vanligaste filtreringsbehovet — folk vet vad de har hemma och ska inte behöva öppna ett modal för det.
+
+*Nivå 2 — Filtermodal via ikon uppe till höger (⊞ eller sliders-ikon):*
+- Muskelgrupp: Bröst / Rygg / Axlar / Armar / Ben / Core / Kondition / Helkropp / Stretching
+- Svårighet: Nybörjare / Medel / Avancerad
+- Övningstyp: Styrka / Kondition / Stretching / Rörlighet
+
+Badge på filterikonen visar antal aktiva filter ("2") så man alltid ser om något är filtrerat.
+
+Filter från båda nivåerna kombineras — t.ex. "Ben" + "Kettlebell" ger övningar som uppfyller båda.
+
+**Övningskort visar:**
+- Namn
+- Primär muskelgrupp (badge)
+- Sekundära muskelgrupper
+- Utrustning som krävs
+- GIF / animationsbild (placeholder i JSX-version, riktig media i React Native)
+- Kort beskrivning av utförande
+- Instruktioner steg för steg
+- Knapp: "Lägg till i schema" / "Logga nu"
+
+---
+
+### 3.5 Träningsschema
+
+**Översiktsvy:**
+- Veckovyn som standard (mån–sön) med swipe till nästa vecka
+- Varje dag visar: passets namn, antal övningar, uppskattad tid
+- Muskelgruppsindikator per dag (färgkodade badges: t.ex. ben = grön, överkropp = blå)
+- Vilodagar markeras automatiskt baserat på föregående dags träning
+
+**Schemalägga ett pass:**
+- Välj dag(ar)
+- Lägg till övningar från biblioteket eller skapa fritt
+- Alternativ: Återkommande (varje måndag / var 3:e dag / etc.)
+- Passet får ett namn och uppskattad tid
+
+**Föreslagna pass:**
+- Baserat på profil och mål genereras 3–5 startmallar
+- t.ex. "Helkropp 3×/vecka", "Push/Pull/Ben-split", "Konditionspass"
+
+**Starta ett pass (aktiv träningsvy):**
+- Övningslista med set / reps / vikt per set
+- Inbyggd timer för tidsbaserade övningar (plank, löpband etc.)
+- Vilotimer mellan set (kan ställas in per övning)
+- Möjlighet att justera vikt/reps live under passet
+- "Nästa set" / "Hoppa över" / "Avsluta pass"
+- Sammanfattning vid avslutat pass
+
+---
+
+### 3.6 Kost- och kalorilogg
+
+**Daglig logg:**
+- Indelad per måltid: Frukost / Lunch / Middag / Mellanmål
+- Kalorier + makros per måltid och totalt
+- Visuell dagstracker: Kalorier kvar av mål (cirkel + siffra)
+- Makrofördelning: Stapel- eller pajdiagram (Protein / Kolhydrater / Fett)
+
+**Lägga till mat:**
+- Sök i databas (Open Food Facts API eller liknande)
+- Skanna streckkod / QR-kod på förpackning (kamerafunktion i React Native, simulerad i JSX)
+- Egna livsmedel kan sparas
+- Favoriter / senast använda snabbval
+
+**Mål och beräkning:**
+- Automatberäkning vid onboarding (Harris-Benedict)
+- Kan justeras manuellt när som helst
+- TDEE-kalkylator med aktivitetsmultiplikator
+- Underskott/överskott visas tydligt
+
+**Makromål:**
+- Gram och procent av totalt kaloriintag
+- Standard: 30% protein / 40% kolhydrater / 30% fett (justerbart)
+
+**Vattenintag:**
+- Dagmål (standard 2,5 l)
+- Snabbknappar: +2,5 dl / +5 dl / +1 l
+- Visuell progress-bar
+
+**Invägning och mätningar (kan avaktiveras):**
+- Vikt (kg) — valfri frekvens
+- Midjemått (cm)
+- Kan läggas till: BMI, fettprocent (manuell inmatning)
+- Påminnelse om invägningsdag (t.ex. varje måndag morgon)
+
+**Veckospårning:**
+- Stapeldiagram: Kalorier per dag senaste 7 dagar
+- Genomsnitt vs mål
+- Makrofördelning per vecka
+
+---
+
+### 3.7 Övningslogg och Progression
+
+**Logg:**
+- Alla genomförda pass med datum, tid, varaktighet
+- Klarmarkering i efterhand möjlig
+- Redigera loggat pass (justera reps/vikt)
+
+**Per övning — progressionsgraf:**
+- Linjediagram: Max vikt över tid
+- Total volym (sets × reps × vikt) per session
+- Bästa insats (PR) markeras tydligt
+- Jämförelse: Denna vecka vs förra vecka
+
+**Statistik:**
+- Totalt antal pass
+- Totalt antal träningstimmar
+- Streak (nuvarande och bästa)
+- Mest tränade muskelgrupp
+- Veckofördelning (vilket säsongsvis mönster)
+
+---
+
+### 3.8 Profil och inställningar
+
+**Profil:**
+- Bild, namn, mål
+- Aktuell vikt + målvikt
+- Progressionskurva vikt över tid
+
+**Inställningar:**
+- Enheter: kg/cm vs lbs/inch
+- Notifikationer: Påminnelser för pass, invägning, vattenintag
+- Invägning: Aktivera/avaktivera + frekvens
+- Tema: Ljust / Mörkt / System
+- Exportera data (JSON)
+- Rensa data
+
+**Streaks och achievements:**
+- Nuvarande streak (dagar i rad med loggat pass)
+- Achievements: "Första passet", "7-dagarsstreak", "100 pass", "PR på bänkpress" etc.
+- Veckomål: x pass per vecka, inställningsbart
+
+---
+
+## 4. Onboarding-flöde (detaljerat)
+
+```
+App startar
+    │
+    ▼ (efter 3 sek splash)
+    │
+    ├── Finns profil? ──── JA ──► Dashboard
+    │
+    └── NEJ
+         │
+         ▼
+    [Steg 1: Välkommen]
+         │
+         ▼
+    [Steg 2: Profil — namn, kön, ålder, längd, vikt]
+         │
+         ▼
+    [Steg 3: Mål — målvikt, syfte, aktivitetsnivå]
+         │
+         ▼
+    [Steg 4: Kalori- och makromål — auto + manuell justering]
+         │
+         ▼
+    [Steg 5: Klart — sammanfattning]
+         │
+         ▼
+    Dashboard
+```
+
+---
+
+## 5. Data-persistensmodell (export-redo)
+
+Designad för att direkt kunna mappas mot AsyncStorage (React Native) eller SQLite (Expo SQLite).
+
+### 5.1 Lagringsnycklar (flat JSON / key-value)
+
+```
+profile                  → ProfileObject
+settings                 → SettingsObject
+exercises_library        → ExerciseObject[]
+workout_schedules        → ScheduleObject[]
+workout_log              → WorkoutLogEntry[]
+food_log                 → FoodLogEntry[]
+measurements             → MeasurementEntry[]
+water_log                → WaterLogEntry[]
+custom_foods             → FoodItem[]
+achievements             → AchievementObject[]
+```
+
+### 5.2 Datamodeller
+
+```typescript
+// Profil
+interface Profile {
+  id: string
+  name: string
+  gender: 'male' | 'female' | 'other'
+  age: number
+  heightCm: number
+  weightKg: number
+  goalWeightKg: number
+  goal: 'lose' | 'maintain' | 'gain'
+  activityLevel: 'sedentary' | 'light' | 'moderate' | 'very_active'
+  calorieMacroGoals: MacroGoals
+  createdAt: string
+  updatedAt: string
+}
+
+// Makromål
+interface MacroGoals {
+  calories: number
+  proteinG: number
+  carbsG: number
+  fatG: number
+}
+
+// Övning
+interface Exercise {
+  id: string
+  name: string
+  category: string
+  muscleGroups: string[]
+  secondaryMuscles: string[]
+  equipment: string[]
+  difficulty: 'beginner' | 'intermediate' | 'advanced'
+  type: 'strength' | 'cardio' | 'flexibility'
+  instructions: string[]
+  gifUrl?: string
+  isCustom: boolean
+}
+
+// Träningsschema
+interface WorkoutSchedule {
+  id: string
+  name: string
+  dayOfWeek?: number          // 0=mån, 6=sön
+  repeatEveryXDays?: number
+  exercises: ScheduledExercise[]
+  estimatedMinutes: number
+  muscleGroups: string[]
+  createdAt: string
+}
+
+interface ScheduledExercise {
+  exerciseId: string
+  sets: number
+  reps?: number
+  durationSeconds?: number
+  targetWeightKg?: number
+  restSeconds: number
+  notes?: string
+}
+
+// Träningslogg
+interface WorkoutLogEntry {
+  id: string
+  scheduleId?: string
+  date: string
+  startedAt: string
+  endedAt?: string
+  durationMinutes: number
+  exercises: LoggedExercise[]
+  notes?: string
+  completedManually: boolean
+}
+
+interface LoggedExercise {
+  exerciseId: string
+  sets: LoggedSet[]
+}
+
+interface LoggedSet {
+  reps?: number
+  weightKg?: number
+  durationSeconds?: number
+  completed: boolean
+}
+
+// Matlogg
+interface FoodLogEntry {
+  id: string
+  date: string
+  meal: 'breakfast' | 'lunch' | 'dinner' | 'snack'
+  foodId: string
+  foodName: string
+  amountG: number
+  calories: number
+  proteinG: number
+  carbsG: number
+  fatG: number
+  barcode?: string
+}
+
+// Livsmedel
+interface FoodItem {
+  id: string
+  name: string
+  brand?: string
+  barcode?: string
+  per100g: {
+    calories: number
+    proteinG: number
+    carbsG: number
+    fatG: number
+  }
+  isCustom: boolean
+}
+
+// Mätningar
+interface MeasurementEntry {
+  id: string
+  date: string
+  weightKg?: number
+  waistCm?: number
+  bodyFatPct?: number
+  notes?: string
+}
+
+// Vattenlogg
+interface WaterLogEntry {
+  id: string
+  date: string
+  totalMl: number
+  entries: { time: string; ml: number }[]
+}
+```
+
+### 5.3 Exportformat
+
+```json
+{
+  "exportVersion": "1.0",
+  "exportedAt": "2025-06-01T08:00:00Z",
+  "profile": { ... },
+  "exerciseLibrary": [ ... ],
+  "workoutSchedules": [ ... ],
+  "workoutLog": [ ... ],
+  "foodLog": [ ... ],
+  "measurements": [ ... ],
+  "waterLog": [ ... ],
+  "customFoods": [ ... ]
+}
+```
+
+Export triggas via Profil → Inställningar → Exportera data → JSON-fil.
+
+---
+
+## 6. Komponentstruktur (JSX)
+
+```
+App
+├── SplashScreen
+├── OnboardingFlow
+│   ├── OnboardingStep1_Welcome
+│   ├── OnboardingStep2_Profile
+│   ├── OnboardingStep3_Goals
+│   ├── OnboardingStep4_Macros
+│   └── OnboardingStep5_Done
+├── BottomNav
+├── screens/
+│   ├── DashboardScreen
+│   ├── ScheduleScreen
+│   │   ├── WeekView
+│   │   ├── DayDetail
+│   │   ├── AddWorkoutModal
+│   │   └── ActiveWorkoutView
+│   ├── LibraryScreen
+│   │   ├── ExerciseSearch
+│   │   ├── ExerciseCard
+│   │   └── ExerciseDetailModal
+│   ├── NutritionScreen
+│   │   ├── DailyFoodLog
+│   │   ├── MacroSummary
+│   │   ├── AddFoodModal
+│   │   ├── BarcodeScanner (stub i JSX)
+│   │   └── WaterTracker
+│   └── ProfileScreen
+│       ├── ProfileHeader
+│       ├── WeightProgressChart
+│       ├── Achievements
+│       └── SettingsPanel
+└── shared/
+    ├── ProgressRing
+    ├── MacroBar
+    ├── WorkoutTimer
+    ├── RestTimer
+    ├── ProgressionChart
+    └── StreakBadge
+```
+
+---
+
+## 7. Fas-indelning
+
+| Fas | Innehåll | Prioritet |
+|-----|----------|-----------|
+| **Fas 1** | Splash + Onboarding, Dashboard, Övningslogg, Träningsschema (grundläggande) | Hög |
+| **Fas 2** | Övningsbibliotek, Progressionsgraf, Streak/Achievements | Hög |
+| **Fas 3** | Kostlogg, Kaloriräknare, Makrospårning, Vattenintag | Medel |
+| **Fas 4** | Barcodeläsare, Open Food Facts-integration, Notifikationer | Lägre |
+| **Fas 5** | Export till React Native, offline-stöd, push-notiser | Migration |
+
+---
+
+## 8. Teknisk stack
+
+| Komponent | JSX-prototyp | React Native (produktion) |
+|-----------|-------------|--------------------------|
+| UI-framework | React (JSX artifact) | React Native + Expo |
+| State | useState / useReducer | Zustand eller Redux Toolkit |
+| Persistens | window.storage API | AsyncStorage / Expo SQLite |
+| Navigation | Tab-state i JS | React Navigation v6 |
+| Charts | Recharts (CDN) | Victory Native / react-native-chart-kit |
+| Barcode | Simulerad | Expo Camera + Barcode Scanner |
+| Animationer | CSS transitions | React Native Animated / Reanimated |
+| Matdatabas | Mock-data | Open Food Facts API |
+
+---
+
+*Dokument uppdaterat: 2025-04-29*