Changelog
What changed and when.
0.9.8
2026-09-10 · latest
- Fixed Hopper's BRAK module sometimes handing you the same exercise twice in one session. "Air squats" lived in both the warmup pool and the strength pool under different ids, so a shuffle could pick it for both — now the strength pool never offers a move that's already covered by a picked warmup.
0.9.7
2026-08-26
- The Profile page is styled again. Promoting UI v2 to the app's only interface deleted the classic stylesheet and rebuilt every screen's markup against the new one — except this one, which kept its old card/field/tab class names with nothing left in the stylesheet to answer them. Every control fell back to bare browser defaults, and goal-specific sections (Strength, Hybrid, Endurance, Longevity) all rendered open at once regardless of which goal was picked, because the CSS class their show/hide logic toggled no longer existed either.
- Fixed a second, quieter bug behind that: toggling the native `hidden` attribute did nothing on any element whose own class set a `display` value (a flex or stack layout, say), because that class's rule always wins the cascade over the browser's built-in `[hidden]` rule. It was masking real state on the Welcome wizard too — sex- and goal-conditional fields there could stay visible after `hidden` was set. A single defensive CSS rule now keeps `hidden` authoritative everywhere.
0.9.6
2026-08-27
- Switching off push, pull or dead hang in Fenris settings now actually removes it everywhere. The week and whole-block views built their wave summary straight from the plan data instead of going through the same enabled set as Today, so a ladder you had just told the app to stop asking about kept reappearing in exactly the two places you were most likely to see it and least likely to trust it again.
- Fixed 'Gjort annat' on a session looking like it never saved. The three fields — what you did instead, hours, pack weight — always rendered empty even right after a successful save, because nothing read the stored value back into them; the detail was landing correctly, just invisible where you typed it. That also meant every retry appended a fresh row to 'Gjort utöver planen' instead of updating the one that was already there. The swap detail now shows back in its own fields and stays a single row, edited in place; the list below holds only what is genuinely in addition to it.
0.9.5
2026-08-20
- The Fenris block is tuned again against what happened. The Thursday before the dress rehearsal becomes an hour in full race kit — boots, socks and pack weight — because the equipment check used to live on the Wednesday session, and a session that gets missed takes its check with it. The opt-out on that day is gone too: after three rest days the legs are not heavy, they are cold.
- The Wednesday ruck in the recovery week is shortened to 75 minutes so the four-hour asphalt walk the next day lands on skin that has recovered. The coach note now says which one gets cut if the feet are still raw — the asphalt, every time. Uniform ground on damaged skin four weeks out buys nothing.
- The one remaining strength session moves from 2 to 31 August. The rules say no heavy work after 31 August and the plan had it on the 2nd, which made the plan and the rules contradict each other — and a rule with an exception in it is a rule nobody remembers. The session itself is unchanged: it is the job that protects muscle mass on the medication.
- The foot log in Fenris is reachable on any day of the block, from a link under the day itself. It used to exist only inside the fuel log, which the plan puts on four days — so the asphalt walk that was designed as a foot test, the whole seven-day field exercise six days before the race, and race day itself had nowhere to record the one thing the rules call the limiter. The long days keep their inline section; nothing already written moves.
- The rules gain two sections. The field-exercise week is not a neutral week — it is an uncontrolled load block sitting exactly where a taper should be, so everything chosen that week is subordinate to standing on the Sunday with intact feet, and the evening walking is the first thing struck. And the race is run in pairs: pace set by whoever is worst off, navigation decided in advance for the hours when judgement fails, and what actually happens if one of you wants to stop — agreed while both are rested, not negotiated at km 45.
- The rules now say when CrossFit comes back. Striking it was a statement about the last four weeks before a 24-hour race, not about the training form: six metcons a week cost more in recovery than they returned, and the one job worth keeping — protecting muscle mass on the medication — is done by thirty minutes of carries and deadlifts. That job does not end when the race does, so "after the race" now carries a date and a reason, because a paused membership with no end date is a membership that quietly becomes a cancelled one.
0.9.4
2026-08-19
- A session in Fenris has three answers instead of one tick: done, done something else, or dropped. A tick could not tell training from a substitution, so a Sunday spent dragging a deer through the forest with a rifle and a pack — closer to the race than any planned session on a known trail — had to be recorded either as a lie or as a hole. All three answers clear the day off the pile; the difference is that the app stops pretending to know which one happened.
- There is now a place for volume the plan never asked for. Anything done on a day, planned or not, can be logged with hours and pack weight, several things per day, deleted one at a time. Answering a session with “done something else” writes both at once — the outcome and what actually happened — so the hunt becomes a row with a number on it rather than free text nobody can add up.
- A week report at /fenris/rapport: seven days back as plain text with a copy button, showing planned against actual, hours under the pack, what is still on the pile and which fuel logs were filled in. It is meant to be pasted into a conversation on a Sunday evening so the rest of the block can be re-planned against what happened rather than what was remembered.
- 27 August becomes the walk home from work — two Swedish miles of asphalt, about four hours at 20 kg — instead of an evening ruck. Volume that costs no extra evening is the volume that actually happens. Home and not there, one direction per day, and in race boots and race socks: asphalt is uniform ground and the same pressure point every step, which makes it a better foot test than a pleasant session, and a hotspot found now is found four weeks early.
0.9.3
2026-08-13
- New sub-app **Fenris** at /fenris, alongside Göta, Njord, Hugin and Saga: a five-week countdown to Para Endurance Race on 19–20 September, for a single invited account. It shows one thing — today's session, why it looks the way it does, this week's push/pull/hang ladder — and records three: whether the session happened, hourly fuelling on the long days, and what the feet looked like afterwards. Nobody else can see it; every address under /fenris answers 404 unless the account is on its list.
- Fenris knows what day it is. A CrossFit booking deadline goes red at the top on the day it falls and the day before it. On 18 September the app hands over to a printable race card instead of a schedule, and on race day itself it shows a countdown and nothing to fill in — there are no phones out there.
- The fuel log is built for hour 14 of a 24-hour race: one row per hour, big +/− buttons, and rows that save the moment they are entered. Without coverage they wait in the browser and are sent when the signal returns. Today's page and the fuel protocol also work in airplane mode.
- Everything logged in Fenris comes back out as JSON or CSV from one link, because the app is meant to be deleted after the race, not kept.
- Fenris now has a way in from VITAIL itself: an entry in the "more" sheet, above Saga. It appears only for the account Fenris belongs to — for everyone else the menu looks exactly as it did, and every /fenris address still answers 404.
- Fenris has its own face. Saved to the home screen it was borrowing VITAIL's icon, which made two different apps look like the same one; it now wears its own wolf, in every size a phone asks for — including a maskable one for Android and a square one for iOS, which reads its own tag and ignores the manifest. The same wolf marks the Fenris row in the menu.
- Today's page in Fenris is a checklist rather than one verdict on the whole day. The CrossFit booking, the session, the tibialis work and each wave ladder are separate rows, ticked in any order, with a count at the top of how many of the day's things are done. A day is not finished in one sitting and the screen no longer pretends it is.
- A booking that has been made stops asking. Ticking it off is recorded against the date it falls due, so booking it the evening before also clears it from the following morning.
- The wave now ends in a set to failure on push and pull, with a box for what you actually got. Dead hang keeps its seconds — hanging to failure the day before a long session is a grip decision worth making on purpose. The ladder reads 5 · 6 · 4 · 4 · MAX.
- The race starts at 10:00, and the fuel protocol and the race card now say so hour by hour: bags numbered against the clock, caffeine in bag 16 at 01:00 and bag 19 at 04:00, and the night correctly placed at hours 14–20 instead of 7–13. At hour 17 nobody should have to do arithmetic.
- The session is ticked off like everything else. "Klart / Delvis / Uteblivet" asked you to decide what "delvis" meant for a rest day before you could record anything; there is now one tick, and whatever is worth saying about how it went goes in the note, in words.
- The day's card no longer repeats itself. The session used to be shown as a card and again as the first row of the checklist below it, which said the same thing twice on the one screen whose whole job is to say one thing. The card carries the tick now, and the list below holds only what is left.
- Fenris had eighteen different text sizes, chosen one at a time. It has six, and the app stops looking unsettled.
- The training block is re-planned from 19 August against what actually happened in its first week. CrossFit is struck entirely — its one real job, protecting muscle mass on GLP-1, is now a single 30-minute session of carries and deadlifts a week, at a fraction of the recovery cost. The last easy run is struck too: the limiter is feet, not fitness, and impact three weeks out buys nothing.
- What replaces them is time under the pack, which the plan was almost entirely missing: outside the two long days it held ninety minutes for the whole remaining block, and now holds thirteen hours. The cancelled shooting competition frees the Sunday after the dress rehearsal for a second loaded session on the previous day’s feet — the only rehearsal there is of setting out on damaged skin and tired legs, which is what hour fourteen of the race asks for.
- Fenris has settings. The recurring things — tibialis, push, pull, dead hang, the fuel log — can each be switched off, so the app stops asking for work you have decided not to do. Switching one off hides its row on Today and drops it from the pile; switching it back on brings both back. The sessions themselves are not on the list: they are the plan, and a switch that empties the plan is not a setting. What you have already ticked is never touched, and the export keeps all of it.
- Undone things pile up where you can see them. An "Ogjort" list under the day carries every session, prehab and wave ladder still unanswered from earlier in the block, newest first, each ticked off where it stands. Nothing is rescheduled and nothing is owed twice — a late tick is recorded against its own original date, because it is a record of what happened rather than a claim about today. Rest and travel days are never on the list: skipping a rest means you trained instead, and no amount of ticking makes Thursday's rest happen on Saturday.
- The wave answers back. Clear a week's hardest set by half again and next week's push and pull ladders come up by a rep or two — capped, never downwards, and always with the reason printed next to the number so a surprising ladder can be traced to the session that earned it. The threshold is a proportion rather than a fixed number of reps: pull ladders are small because pull-ups are hard, and a flat threshold would have frozen them at a max nobody weak at them would ever reach.
- Fenris looks finished. The charcoal screen now has depth and a quiet wolf watermark, the mark sits in a real brand strip with the countdown, cards catch a warm light instead of reading as flat boxes, the bottom bar carries icons, and the day's checklist grows a thin progress line — still dark-only, still glove-sized, still offline, just no longer looking half-drawn.
0.9.2
2026-08-12
- The redesigned interface (previously an opt-in "try the new look" toggle) is now the only interface. The classic pages, the toggle switch on your profile, and the login-page link back to the old look are gone — everyone gets the same, more polished app from now on.
- Fixed a privacy leak the redesign had introduced: the shared "more" menu was showing your full email address on the Saga film-list page, which used to show only your list name. It now shows nothing there, matching how it always behaved before.
0.9.1
2026-08-12
- Saga rows now say where the film is: a badge per streaming service, linking straight into that service's own search instead of routing you through JustWatch. VAR? is still there for films we have not found anywhere.
- A new "Kan ses nu" filter narrows the list to what is on the services you have, which finally lets one question cover the whole evening: max 1h 45m, unseen, and on something we pay for. Tick your services under the cog. SVT Play always counts, because it is free.
- The list itself never shrinks behind your back: the filter is off unless you switch it on, and films with no known service stay visible rather than quietly disappearing.
- Availability is a snapshot with its date printed under the list, not a live lookup. Nothing about a page load depends on anyone else's service being up. SVT Play rotates films fastest of all, so the footer says outright that the service always knows better than the badge.
0.9.0
2026-08-11
- The film list is now called **Saga** and lives at /Saga. Named after the Norse goddess of storytelling, and after half the cinemas in 20th-century Sweden. Old links to /Movies still work. The heading is the app's name now, with the film count moved to the line below it.
- The VAR? link had the wrong JustWatch address and landed on a dead page; it now goes to the real Swedish search.
- Your Saga list is now your own. It used to be one list for the whole installation, which was right when two people shared it and wrong as soon as anyone else had an account. Under the cog you can share it with one other person: you each type the other's address, and when both have done it the lists merge, keeping every tick from both. Nobody can attach themselves to your list by knowing your address. Stop sharing and you each keep a full copy.
- The "i" panel no longer claims the list is shared. It explains that it can be, and where.
- Saga has its own front door at /Saga/login, with its own look and nothing about training on it, and every Saga address leads to it: opening the list while signed out asks you to sign in there rather than on the training page, a lowercase /saga/login no longer dead-ends, and signing in takes you to the page you asked for. An account created there gets Saga and nothing else: no training questions before it will show you anything, no nav full of doors that do not open, and it lands on the list at every login. The shared page furniture is gone from Saga too — no feature-request lightbulb, no EN/SV switch on a Swedish-only list, and no "VITAIL — physiological decision engine" along the bottom of a film list. Existing VITAIL accounts and their login page are untouched.
- The Nordic Wellness white-label is removed. It reached further than it looked — a second string catalogue, session state that survived logout, conditionals in both interfaces, and a brand-switch button on the login screen. All of it is gone; ordinary dark and light theming is untouched.
0.8.5
2026-08-11
- /Movies — pick by how long you have, not just by what you feel like. Every one of the 419 films now carries its runtime, shown on each row next to the year, and a new Speltid slider caps the list at 1h 30m, 1h 45m, 2h, 2h 15m, 2h 30m or 3h. Because nobody actually thinks in minutes at nine on a Sunday, the slider answers in clock time: set it and it tells you "Startar du nu 19:04 är du klar 20:49". The random pick respects the cap too — it never widens the pool past the length you asked for — and it now says when you'd be done with the film it drew. Runtimes are approximate cinema lengths.
- /Movies — the decade filter is a span instead of a single pick. Two handles on one track, so you can ask for 1970-tal till 1990-tal in one go rather than stepping through one decade at a time. The handles cannot cross, and the whole span is the default.
- /Movies — a new "i" button next to the title explains why the list exists: what it is for, that it is deliberately fixed and finite, that ticks are shared between both accounts, and why each film gets only one spoiler-free line. The heading text below the title is correspondingly short again.
- /Movies — the list can be sorted: list order, shortest or longest first, highest rated, newest or oldest, or title A-Ö. With a length cap set, "shortest first" is usually the whole question answered.
- /Movies — filters survive a reload, and the link carries them. Decade, genre, length cap, sort and search now live in the address, so you can send someone the exact shortlist you are looking at rather than describing it.
- /Movies — watched films now say who ticked them off and when ("du · idag", "susanne · 8 aug"). The list has been shared since the last release, but nothing on screen showed it, so it read like a merged list rather than a joint one.
- /Movies — a star marks a film as one you want to see. Unlike watched, this one is per person, which makes "Båda vill" a filter you can actually use: star things independently, then let the shuffle pick from what you both flagged. The shuffle stays inside that shortlist rather than widening out of it.
- /Movies — search covers the year and the genre too, so "1975" and "skräck" find what is printed on the row in front of you. Typing is also markedly smoother: only the list redraws per keystroke instead of the entire page.
- /Movies — keyboard use no longer loses your place: ticking a film off keeps focus on that film instead of dropping to the top of the list.
- /Movies — the VAR? link goes straight to a JustWatch search rather than routing through a Google search first.
0.8.4
2026-08-08
- New private sub-app: /Movies — a searchable, filterable checklist of 419 films you're expected to have seen, with approximate IMDb ratings, spoiler-free one-liners, genre pills, a decade slider, and a "pick a random unseen film" shuffle for when you can't face browsing. Each title links straight out to a JustWatch lookup, so you find out which service actually has it instead of opening six apps. Ticking a film off marks it for everyone invited — it is one shared list, so you can work through it together without both having to remember what the other has seen. Available to invited accounts only, via a film icon in the app navigation. Swedish only.
0.8.3
2026-07-20
- Göta — For Time workouts are right-sized for the audience: no more horror volumes like 300 burpees or 300 box jumps. Each movement now has a rep ceiling based on how hard it scales — burpees and box jumps top out at 21-15-9, kettlebell swings at 50-40-30-20-10, while light movements (double-unders, air squats, sit-ups, lunges) can still fill the big 100-80-60-40-20 ladder. A "two separate races" session now checks that both races fit the time cap (previously only the first was checked, so a brutal second block could slip through), and the per-rep time estimates for burpees, box jumps and double-unders were made realistic instead of machine-pace.
- Hopper gets the same two-block For Time fix: the second race now respects the high-fatigue rep cap and is checked against the time cap, so it can no longer hand you 300 burpees in the back half.
0.8.2
2026-07-15
- Today check-in — pick your session: endurance athletes now choose today's post-it instead of the engine silently deciding. One option per focus discipline (the planned rotation pick is pre-selected), and on ruck weeks with an event on the calendar, the weekly long ruck appears as its own option with its real cost up front ("~36 km, ~7 h 30 min").
- Honest long-ruck durations: choosing the long ruck builds it with a true time-on-feet estimate from your logged loaded pace (fallback 12:00/km) — the workout header now says "~7 h 30 min est." instead of pretending it fits in "~60 min", and a note makes clear the daily time budget doesn't apply. The regular budget-fitting session no longer carries the multi-hour distance target in its coaching; instead it reminds you the long ruck is still on the board this week. The program itself is unchanged.
- Clearer session picker: the check-in options now render as proper selectable cards — a title, a detail line ("~36 km · ~8 h", "today's plan"), and an obvious selected state — instead of cramped text pills.
- Göta (/gota) fixes: the workout timer now keeps true wall-clock time even when the phone switches apps or the screen locks mid-block; if the app auto-eases your session after two "too hard" ratings it now says so in the workout text instead of downgrading silently; the feel history summary is shown after each finished session; saved workout images are named gota-pass instead of hopper-pass; and a broken error message on failed startup is fixed.
- Göta offline: the app now loads with zero external requests — the Roboto font and the screenshot library are bundled and pre-cached, so an installed Göta works fully without internet. Versioned assets are also cached properly, making repeat loads on gym wifi much faster.
- Göta welcome note: a friendly card on the session-length screen sets expectations — the best workout is the one that actually happens, this isn't full-scale programming, and if a workout looks wonky you just generate a new one. Includes a feedback email link, can be dismissed with "Got it", and re-enabled any time from the config screen. English and Swedish.
- Göta is now Swedish by default: first-time visitors get Swedish straight away (the page itself, before any script runs, is Swedish too), and the language toggle still switches to English with the choice remembered.
- Göta copy polish: the install banner now spells Göta correctly, and the screenshot error no longer blames your network (the library is bundled — it says to reload the app instead).
- Göta generator fix: on longer sessions the generator could get stuck on a rep scheme it couldn't build a workout for and show "could not find a new workout" — it now falls through to the next scheme (ported from Hopper), and EMOM sessions always end on a complete rotation. The help screen also gained the five missing bodyweight movement descriptions (jumping jacks, air squats, sit-ups, lunges, mountain climbers).
- Hopper gets the Göta reliability fixes: the workout timer keeps true wall-clock time when the phone switches apps or the screen locks mid-block, the screenshot library is bundled instead of loaded from a CDN, versioned assets cache properly for faster repeat loads, and the install hint now appears on modern iPads too.
- Göta & Hopper — varied round splits: rest between rounds now scales with round length (short rounds 1 min, mid rounds 2 min, only 8+ min rounds get 3 min), and the round count varies between sessions. A 45 min session now comes out as 5×7 min/2 min, 6×5/2 or 4×8/3 instead of always the same 5×6/3 — no more resting longer than the work deserves.
0.8.1
2026-07-14
- Bodyweight progression cycle (opt-in, all goals): turn it on per exercise — push-ups, pull-ups, dead hang — on Profile with your current max, and every workout gains a short superset built from it. Sets are varied and deliberately submaximal (from a max of 6 push-ups you might get 4-5-3-4-2), so every session ends in success; total volume nudges up over a 3-week wave and week 4 is a relaxed re-test that updates your max.
- Cycle progress: re-test results land in your records history, and a new Bodyweight cycle card on Progress / My Records shows your max trend per exercise, the current cycle week, and lifetime volume totals. Completing a cycle session, unlocking a new week, and setting a new max each get their own celebratory message. Undoing a logged workout restores the cycle state. English and Swedish.
0.8.0
2026-07-12
- New interface (opt-in beta): a completely redesigned VITAIL — bold gradient look, bottom tab bar on mobile (side rail on desktop), a whiteboard-style workout screen with tappable set checklists and an inline rest timer, and a streamlined daily check-in. Try it with the "Try the new interface" link on the sign-in page, or switch any time from Profile → "Use new interface". The classic interface stays the default and is completely unchanged — you can switch back whenever you like.
- Progress (new interface): a new Progress tab brings your training data together — training consistency over the last 12 weeks against your weekly target, strength PR trends per lift, endurance time trends per distance, conditioning-benchmark bests, plus your readiness mix and effort trend from logged sessions.
- New interface details: works offline like the classic one, follows your dark/light theme and language (English and Swedish), and no longer loads any third-party fonts.
0.7.14
2026-07-11
- Swedish: workout sessions are now fully translated — the training split, session structure notes, recovery/warm-up copy, time-budget adjustments, and all endurance session text (base/build/quality phases, recovery days, brick sessions) now follow your language setting instead of falling back to English. Error messages on the Profile and My Records forms are translated too.
- Day boundary: the app's idea of "today" (your workout draft, the check-in unlock, the weekly progress bar) can now follow a configured app timezone instead of the server clock, so a workout built late in the evening no longer disappears at the server's midnight.
- Account safety: deleting an account now signs it out everywhere immediately (previously a logged-in device could keep using a deleted account), removes all prehab and skill-progression history, and detaches feedback posts. Granting or revoking admin access now applies without re-login.
- Assessments: the strength and endurance assessments now reject implausible entries (extreme rep counts, over-cap weights, unknown test distances) so a typo can't save an absurd personal record that skews every future session.
- Profile: choosing "Prefer not to say" for sex now sticks — saving the profile no longer silently resets it. A saved event/race context is also no longer wiped by an unrelated profile save.
- Security: all forms and actions are now protected with CSRF tokens, on top of the existing cookie protections.
- Small fixes: the feedback (lightbulb) button now highlights when you're on the feedback page, the first-visit intro card stays dismissed once you close it, and sign-in counts are tracked correctly.
0.7.13
2026-07-05
- Workout plan: a new "Export plan" button on the plan page downloads your full training program as a Markdown file — phases, weekly structure and a sample of your upcoming sessions. For a race-focused ruck program it also includes your event focus, a week-by-week long-ruck distance ladder counting down to your event, and your 3×/week prehab routine. Works for every goal (strength, hybrid, endurance, longevity). English and Swedish.
- Plan export detail: exported sessions now show the correct discipline (e.g. "Ruck") instead of an internal lift name, with each session's pace/intensity and coaching. Endurance plans gain a week-by-week schedule (each week's long-ruck target, discipline mix and dates counting down to your event), and the event-focus section now appears whenever an event date is set — with a hint to add your event distance when it's missing. English and Swedish.
- Profile: your event date and distance are now a clearly labelled "Event / race goal" section on the Training tab instead of being buried in Account → Advanced, so they're easy to find and set. The Workout plan page now nudges ruck athletes who haven't saved a race to add one. English and Swedish.
- Today: a motivational weekly progress bar shows how many days you've trained this week against your target, with an encouraging message that builds from a fresh-week nudge to a week-complete celebration. English and Swedish.
- Progress tracking: the current-week highlight now advances with the sessions you actually log (a fresh plan reads week 1). For endurance plans with an event date, the plan instead anchors to your race — placing you at the week you should be training to peak on race day, even if the race is sooner than the full program — and a new pace badge on the Today and Workout plan screens shows whether your logged training is on track, behind, or ahead of that schedule. The exported plan's week-by-week schedule follows the same real countdown so its dates never fall in the past. Explained inline on the plan page. English and Swedish.
0.7.12
2026-07-03
- Njord: UV index added to daily forecast — shown in both Summary and Sources views (provided by Open-Meteo).
0.7.11
2026-06-25
- Workout logging: you can now record the reps you actually completed on each set of your main lift (and flag when form broke down) when you finish a session — an optional "Log your sets" panel on the completion screen. Your logged reps appear in the workout log alongside the prescription, so you can see prescribed-vs-achieved at a glance. This is the foundation for adjusting future sessions on what really happened rather than a single effort rating. English and Swedish.
- Today screen: a compact "where you are" band now shows your current week of the program, the active training phase, and a progress bar across the block — so the build → peak → taper → deload arc the engine already plans is finally visible on your daily screen instead of buried on the plan page. English and Swedish.
- Workout screen: a prominent "Today's adjustments" strip now spells out why today's numbers differ — when loads were eased for a return-from-layoff ramp, trimmed for a race taper, or nudged up/down by your recent effort — instead of leaving it buried in the collapsed coaching notes. English and Swedish.
- Accessibility: the live estimated-1RM readout on the strength assessment now announces itself to screen readers as it updates while you type, and the readiness dots in your workout log (sleep, hydration, fatigue) now carry proper text labels instead of relying on hover tooltips alone.
- Skill & power progression: your CrossFit gymnastics drills (double-unders, toes-to-bar, pull-ups, muscle-ups, handstand push-ups) and Olympic-lift/power blocks now show a level (e.g. "Level 2 of 4"), and when you finish a session you can rate how the drill felt — "nailed it", "about right", or "too hard". Rate it up and the next time that movement comes around you get the harder progression; rate it down and it eases off. The difficulty now follows your real ability instead of a fixed experience setting. English and Swedish.
- Hybrid training: when a session mixes heavy lifting with an aerobic or conditioning block, the workout screen now shows a short ordering tip — lift first when strength is the priority, or do your endurance quality first and treat the lifting as maintenance — so the two don't blunt each other (the interference effect). English and Swedish.
- Multi-sport athletes: the Today screen now shows a week-at-a-glance strip of your training disciplines — your real swim/bike/run mix for the week (from your per-discipline frequency), with the session that's up next highlighted — so a triathlete can see the shape of the week, not just today. English and Swedish.
- Warmups: your movement-prep now includes a short, targeted mobility drill — rotating through hips, upper back, ankles/feet and shoulders by the day — so joint prep is part of the warmup for every goal, not just a separate longevity card. (The bodyweight/home track already builds its own mobility prep, so it isn't doubled up.) The longevity Today mobility card stays as your daily-habit reminder, and now matches the day's warmup focus. English and Swedish.
0.7.10
2026-06-24
- Swedish wording: fixed false-friend translations in benchmark-WOD text — "ring rows" now reads "ringrodd" and "dead hang" reads "passivt häng" instead of the English terms. A canonical movement glossary plus a CI lint now keep these from creeping back in.
- New lifters: the workout screen now shows a short "How to do this lift" card on your main lift — three or four plain-language cues plus the most common mistake to avoid — so a beginner reading "Squat 5×5" actually knows how to squat. Shown for beginners only, in English and Swedish.
- Longevity: cardio is now named and dosed the way the evidence frames it — a Zone-2 aerobic base (easy, conversational pace) most sessions, with one short VO2max interval session rotated in about once a week — instead of a generic conditioning block. Applies to both the barbell and bodyweight longevity tracks, in English and Swedish.
- Longevity: a short "Today's mobility" card now appears on the Today screen — a two-to-three-minute routine whose focus rotates daily (hips, upper back, ankles/feet, shoulders) so joint health is front-and-centre rather than buried in an accessory. English and Swedish.
- Coming back from a break: if you return after a layoff of two weeks or more, VITAIL now automatically eases your working load (more for a longer break) and restores it over your next few sessions, with a "welcome back" note on the lift — so you ramp back in instead of jumping straight onto old maxes.
- Injuries: onboarding and Profile now let you tick specific injury areas (shoulder, lower back, knee, hip, elbow, wrist, ankle/foot, neck). VITAIL folds a concrete, localized caution for each into your sessions — alongside any free-text notes — so it can train around the right thing. English and Swedish.
- Triathlon: if you train both cycling and running, VITAIL now rotates in a brick session about once a week in the build/quality phases — a steady bike straight into a run off the bike, with transition (T2) coaching — the race-defining workout. English and Swedish.
- Multi-sport: endurance athletes can now set how many sessions per week each discipline gets (in Profile). VITAIL spreads them across the week — e.g. swim 1×, bike 2×, run 3× becomes an interleaved schedule rather than a flat round-robin. Leave it blank to keep the even rotation.
- CrossFit: mixed-metcon sessions now include a rotating skill-practice block for the gymnastics movements that actually gate performance — double-unders, toes-to-bar, pull-ups, muscle-ups, handstand push-ups — with the drill difficulty matched to your experience level. English and Swedish.
- Autoregulation: the effort you log now adjusts load, not just volume — a run of easy-feeling sessions nudges your working weight up a touch (so a strong stretch actually progresses), while consistently maximal sessions ease the load slightly as well as trimming a set. Still skipped on a taper, a low-readiness day, or a return-from-layoff ramp so changes never compound.
- Strength: a new "accessory focus" setting in Profile lets you bias accessory work toward your weak points (upper back, posterior chain, triceps, biceps, core, grip, shoulders, calves). VITAIL rotates through the ones you pick instead of a generic default. English and Swedish.
- Cycle tracking: add your cycle length and last period start in Profile and VITAIL now predicts your cycle phase each day — so the luteal-phase back-off happens automatically instead of only when you remember to log it. A phase you pick on Today still overrides the prediction.
- Hyrox: sessions now lead with compromised running — run → station → run intervals at race pace, the way the race is actually won — and the round count periodizes across your mesocycle (building through weeks 1–3, tapering in week 4). English and Swedish.
- Readiness: you can now log your morning resting heart rate on the Today check-in. When it sits well above your recent baseline — a classic recovery red flag — VITAIL eases the session automatically. Entirely optional; leave it blank to ignore.
- My Records: an Endurance progress panel now shows a sparkline of your logged times over time for each discipline and distance (run, bike, ski, swim, ruck), with the change since your first entry — faster reads as up. Same informational, non-gamified style as the strength trends.
- Event taper: the race/meet taper now also applies to the bodyweight and home-gym longevity tracks — previously it only kicked in on the barbell and endurance paths. Set an event date and your bodyweight sessions ease off into the event too.
- Endurance variety: every phase now rotates through three distinct session types instead of two — a long slow distance session in the base phase, a threshold session in build, a VO2max session in quality, and a true recovery session in the absorb week — so higher-frequency athletes get more polarised, less repetitive weeks. English and Swedish.
- Power & technique: CrossFit (mixed-metcon) sessions now add a rotating Olympic-lift technique EMOM (snatch, clean, jerk), and longevity sessions add a rotating power block (jumps, throws, fast concentrics) — the highest-yield, lowest-risk additions for athleticism and bone density — with difficulty matched to your experience level. English and Swedish.
0.7.9
2026-06-22
- Onboarding: the strength and endurance assessment error messages (e.g. "enter at least one lift") are now localized — Swedish users no longer see raw English when a submission is empty or can't be estimated.
- Benchmark WODs: when a session prescribes a named CrossFit WOD (Fran, Cindy, …), you can now record your result (mm:ss for time, or rounds+reps for AMRAP) on completion. My Records shows a per-WOD history, newest first, with PR markers so you can see your re-test progress over time.
- New lifters: the Today screen now shows an inline "main-lift numbers" card with sensible starting 1RMs for your experience level (editable), instead of just linking off to My Records — so a first session builds with realistic loads in one tap.
- My Records: a Strength progress panel now shows a small sparkline of your estimated 1RM over time for each main lift, with the change since your first entry — your data and patterns, no streaks or badges.
- Event date: set a race or meet date in Profile and VITAIL now tapers session volume as it approaches — a peak week (~2 weeks out), a taper (final week), and activation-only on event day, with a coaching note on each affected session.
- Autoregulation: the effort rating you log after a session now feeds the next one — several maximal-feeling sessions in a row trim a set to protect recovery; consistently easy ones add a nudge to push the top set. Applies on normal days only (never stacked on a taper or a low-readiness back-off).
- Swimming: swim is now a full endurance discipline — pick it as a focus, log pool and open-water times (100m–3.8k), and get pace per 100m. Enter both a 400m and 200m time trial and VITAIL computes your true Critical Swim Speed (CSS) and sets training zones around it; sessions are real swim workouts (warm-up, drills, CSS interval sets, pull/kick, open-water sighting/drafting practice, cool-down) in English and Swedish, scaled to your available time.
- Rucking: loaded marching is now a discipline of its own — pick Ruck as your focus, log ruck times (5k–80k) for a loaded pace per km and an event-distance projection, and get Zone-2 time-on-feet sessions built around the long ruck (terrain, back-to-backs, a peak dress-rehearsal, foot care and fuelling cues, EN/SV). Because most ruckers train strength elsewhere, ruck sessions skip the barbell maintenance block, and the event-date taper now applies to endurance too.
- Ruck event coaching: set an event date and an event distance (e.g. an 80 km march) and VITAIL now tells you each week exactly how far this week's long ruck should be — laddering the distance up through a peak (with a back-to-back option), then tapering into event week — so the app carries you through the whole build, not just today's session.
- Ruck prehab: a standalone whole-lower-limb prehab habit (shin/tibialis, calf/soleus, foot, ankle, hips and balance, plus a phase-2 impact progression) now appears as its own card on Today for ruck athletes — every day, including your CrossFit and rest days. It is decoupled from the ruck session on purpose (you should not load shins right before a long ruck). Tick "Mark prehab done" and the app tracks your 3×/week adherence.
0.7.8
2026-06-21
- Workout: new Whiteboard toggle strips the page down to essentials — lift, warm-up ramp, work sets, and a compact 'Then' list. All details remain one tap away under Session details.
0.7.7
2026-06-19
- My Records: time fields for ski/row/run/bike PRs now use a text keyboard on mobile (was numeric-only) so ':' can be typed for mm:ss / h:mm:ss entries; invalid formats now show a clear, localized error.
- My Records & endurance assessment: saving a time now pops up a confirmation showing how it was read (e.g. "3:12"), or a warning listing entries that don't match a valid time format, with Edit / Save choices before submitting.
0.7.6
2026-06-15
- Training: equipment preference now drives session content — dumbbell-only users get dumbbell variants with appropriate loads; home-gym users get bodyweight longevity sessions.
- Training: warm-up ramp added to every barbell/dumbbell session (collapsible, shows empty-bar → working-weight progression).
- Training: beginner progression cadence increased to every 2 days (classic novice linear model) instead of weekly.
- Training: secondary and accessory exercises now rotate across 3 variants per lift to reduce monotony.
- Training: endurance modality rotates across all selected activities instead of always picking the first.
- Training: quality-phase endurance sessions now prescribe concrete intervals (e.g. 5×1000m @ pace) when training paces are available.
0.7.5
2026-06-15
- Onboarding: registration hero text, goal descriptions, and program descriptions rewritten to be beginner-friendly — no gym jargon.
- Onboarding: wizard reordered to lead with goal selection and training days before asking personal details; steps reduced from 5 to 4.
- Onboarding: default experience level changed from Intermediate to Beginner so new users get safe starting loads.
- Onboarding: equipment selection (full gym / dumbbells / home) added to the wizard so first sessions match available gear.
- Onboarding: health disclaimer collapsed into an expandable summary to reduce registration-page intimidation.
- Onboarding: summary step now includes a sample-session preview per goal so users know what to expect.
- Onboarding: 'Longevity' goal gets a 'Great for getting started' badge; no goal is pre-selected.
- Today: first-visit orientation card explains how the daily check-in works; readiness hint shown for the first few sessions.
- Today: first generated session shows a welcome flash instead of the generic confirmation.
- Login: three value-proposition bullets added below the hero subtitle.
0.7.4
2026-06-15
- Internal: moved ~2 500 lines of inline workout/training data from Python source into JSON data files (conditioning workouts, bodyweight tiers/mobility/conditioning, endurance templates) — makes content editing and translation safer and reduces merge conflicts.
0.7.3
2026-06-15
- Engine: the endurance assessment page now warns that distance estimates far from the one you entered (e.g. a 10K test used to predict a 90K ski marathon) are rough, and that you should enter your own time once you have one.
- Fixed: today's endurance session (run/erg/bike/ski description, intensity, coaching notes, pace targets, and the strength-maintenance accessory) is now translated into Swedish for Swedish-locale users — previously this content was always shown in English regardless of language setting.
- Fixed: today's longevity bodyweight session (push/pull/squat prescriptions, hinge complement, mobility prep, conditioning movements, and easy aerobic block) is now translated into Swedish for Swedish-locale users — previously this content was always shown in English regardless of language setting.
0.7.2
2026-06-14
- Engine: Hyrox hybrid sessions now always use the GVT barbell template (10x10 @ ~60% 1RM, scaled by time budget), regardless of experience — previously, intermediate and beginner users got a 5x5/Linear intensity (~75-81% 1RM) paired with GVT-calibrated set counts, making the session far too heavy for its volume.
- Engine: an approved event/goal context on the profile now actually skews today's secondary, accessory, and aerobic blocks toward ruck/endurance/long-duration prep — in both the live Today session and the Workout Plan preview.
- Engine: readiness now also looks at your last 3 logged sessions — if today is fatigued and at least 2 of those were also fatigued-or-worse, the day escalates to overreached (forced recovery) instead of a normal fatigued session.
- Engine: Linear, 5x5, and GVT programs now cycle through a 4-week block with a built-in deload week (lighter sets/reps/intensity plus a coaching note), advancing once all four main lifts are logged — mirroring the existing Wendler 5/3/1 wave.
- Fixed: the 404 and 500 error pages now render with the full app shell (navigation, theme, footer) instead of a bare unstyled page.
- Fixed: the strength assessment form (Assess 1RM) now correctly converts pound entries to kilograms before estimating PRs — previously lb users got 1RM estimates roughly 2.2x too high. The weight field now also shows the correct unit (kg or lb) based on your profile setting.
- Fixed: Profile page hint text (experience, hybrid program, strength program, accessories, weight unit) now renders with its intended tighter spacing — duplicate `class` attributes were silently dropping the `hint--tight` styling.
- Fixed: cache-busted CSS version was out of sync between the service worker's precache list and the stylesheet link, so installed PWAs could keep serving a stale vitail.css — both now point at the same versioned URL.
- Engine: the endurance absorb week (meso week 4) now also reduces session frequency for users training 4+ days/week — one slot per week becomes a rest or easy cross-training day instead of another structured session, on top of the existing volume reduction.
- Engine: endurance sessions now rotate through 2 variants per phase (base/build/quality/absorb) based on where you are in your lift rotation, so the same week no longer prescribes an identical run/erg/bike/ski session on every training day.
- Fixed: the onboarding summary (step 5) now shows your goal and experience level translated into your chosen language, instead of always showing the raw English value (e.g. "Strength"/"Intermediate" for Swedish users).
- Fixed: the Feedback page's back link, sort buttons (Newest/Most popular), and admin reply form are now translated instead of always showing English text to Swedish users.
- Fixed: the sign-in page's "Switch to VITAIL" link (shown on the Nordic Wellness login) and the workout page's "Show timers" toggle and "reps" label are now translated instead of always showing English text.
- Fixed: the training-state badges on the Logs page now use dedicated 2-letter short codes (e.g. "ST", "FR") instead of truncating the translated state label to 2 characters, and the readiness fatigue tooltip now shows your translated fatigue level instead of always showing the raw English value.
- Fixed: validation errors on the Reset Password page (e.g. password too short, passwords don't match) now render with the same accessible error styling as the sign-in page (role="alert" + red border) instead of an inline style with no screen-reader role.
- Removed: the unused legacy register.html template — registration has used the sign-in page's Register tab for some time.
- Fixed: the disabled Workout nav tile (shown before today's check-in) is now exposed to screen readers via aria-disabled with an explanatory label instead of being hidden entirely via role="presentation"; the Account nav menu's expand/collapse state is now announced via aria-expanded, and a redundant aria-label on its toggle was removed.
- Fixed: the Gym Timer page's root container no longer uses the overly broad role="application" (which would tell screen readers to hand over all keyboard handling); it now uses role="region" instead. The timer page's own copy of the bottom nav has also been updated to match: the disabled Workout tile now uses aria-disabled with an explanatory label instead of role="presentation", and the Account menu announces its expand/collapse state via aria-expanded.
- Fixed: on the Workout page, the collapsible Prep and Recovery sections no longer get a second, conflicting keyboard/click handler layered on top of their native expand/collapse control — previously every workout tile (including these two) was made into its own role="button" tab stop for a "focus this block" feature, creating two tab stops and clashing click behaviour on the same element.
- Fixed: the offline service worker now precaches the set timer chip, block timer, and Nordic Wellness theme assets used by the Workout page — previously these were only cached after a user had visited that page online at least once, so a first-time offline visit to Workout could fail to load them.
- Security: hosted deployments now default session cookies to Secure + SameSite=Lax automatically — previously this required setting SESSION_COOKIE_SECURE/SESSION_COOKIE_SAMESITE env vars manually, and Flask's weak defaults applied if they were forgotten. Explicit env var settings still override the default.
- Security: encrypted profile fields (sex, menopause status, approved event summary) now log a warning if they fail to decrypt — e.g. after VITAIL_ENCRYPT_KEY is rotated or set to an invalid value — instead of silently falling back to the stored value with no record of the failure.
- Engine: the mixed-metcon (CrossFit-style) hybrid track now avoids repeating a named benchmark WOD you've done in your last 5 sessions, picking a fresh one from the rotation instead of the same workout on a predictable schedule.
- Engine: bodyweight longevity training no longer dead-ends at the top strength tier — once a day reaches its final tier, the main lift now rotates through 3 advanced variations each session (e.g. wall walk-to-handstand and pseudo-planche push-up for Push, typewriter pull-up and tuck front lever for Pull, shrimp squat and deficit pistol squat for Squat), each with its own progression target.
- Engine: Hyrox hybrid sessions now call out a daily-rotating "focus station" (one of the 8 race stations) alongside the full station list, giving real session-to-session variation instead of leaving the "pick ONE" choice entirely up to you every time.
- Engine: bodyweight longevity conditioning now rotates through 6 movement combos per day instead of 4, adding 7 new movements (high knees, skater hops, Russian twists, star jumps, plank shoulder taps, bicycle crunches, side plank with reach-through) so Burpees/Mountain climbers/V-ups no longer dominate the rotation.
- Admin: sensitive actions (removing an account, replying to feedback, deleting your own account) are now recorded in a new audit log, viewable by admins at /admin/audit-log — entries store masked emails only.
- Security: /login, /register, and /forgot-password now rate-limit repeated attempts from the same IP (10/min for sign-in and registration, 5/min for password-reset requests) — previously these endpoints had no protection against brute-force or spam.
- Bifrost: tema- och språkknapparnas aria-label uppdateras nu till rätt språk vid byte (tillgänglighet för skärmläsare).
- Njord: tema- och språkknapparnas aria-label uppdateras nu till rätt språk vid byte (tillgänglighet för skärmläsare).
- Njord: lejonvattenmärket cachas nu av service worker för korrekt offline-vy.
- Njord: modellsäkerhetsmärket går nu att trycka på för en förklaring, med färgkodning (grön/gul/röd) för snabb avläsning.
- Njord: NOAA-vinddata tolkas nu korrekt för intervall (t.ex. "10 to 15 mph") och alla 16 kompassriktningar mappas till gradtal.
0.7.1
2026-05-13
- Hugin: Plutonchef-läge — toggle GRUPPCHEF/PLUTONCHEF, klistra in gruppchefsrapporter och slå ihop till en summerad plutonsrapport.
- Hugin: rapportformat uppdaterat till brackets [P]/[E]/[D]/[A]/[R]/[S].
- Alla appar: integritetsnotis (ingen molnlagring, all data lokalt) och uppmaning att spara på hemskärmen.
- Hugin & Bifrost: appikon med vit symbol mot grön bakgrund för hemskärmen.
- Bifrost: ny hubbsida med direktlänkar till Hopper, Njord och Hugin.
0.6.0
2026-05-12
- Hugin: ny subsite för snabb PEDARS-rapportering (P/E/D/A/R/S) med formulär, rapportgenerering och kopiering till urklipp.
0.5.99
2026-05-11
- Njord: varje dagkort har en ▾-knapp som expanderar en 6h-periodvy (00–06, 06–12, 12–18, 18–24) med temp och vind per källa — YR, SMHI och Open-Meteo.
- Njord: fetchAll samlar perioder parallellt med dagdata utan extra API-anrop för YR/SMHI; Open-Meteo hämtar hourly i samma request.
- Njord: Summary-vyn visar nu vindriktning tillsammans med vindstyrka (konsensusriktning via cirkulärt medel av tillgängliga källor).
- Njord: Sammanfattning är nu standardvy för nya besökare (tidigare Källor).
0.5.98
2026-05-11
- Njord: Sources-vy visar nu vindriktning (t.ex. '5 m/s SW'), upplevd temperatur ('Känns') och luftfuktighet ('Fukt.') per källa.
- Njord: Summary-vy visar Känns och Fukt. som konsensusrader (median av tillgängliga källor).
- Njord: Open-Meteo hämtar apparent_temperature_min/max direkt från daily-API; YR och SMHI beräknar kyleffekt per timme med JAG-formeln.
- Njord: undviker missvisande vindriktning när riktningsmedel tar ut sig (t.ex. motsatta vindar) — kompasssuffix utelämnas i stället.
0.5.97
2026-05-11
- Njord: ny app-ikon — drakens huvud från vikingaskeppet, vitt på mörkgrön bakgrund (192 px, 512 px, maskable).
- Njord: byter font-display från optional till swap + lägger till rel=preload för stencil-typsnittet så det laddas korrekt vid första besök.
0.5.96
2026-05-11
- Njord: fix crash i renderPanel när getCached returnerar null — förhindrade att prognoser visades för nya orter.
0.5.95
2026-05-11
- Njord: ersätter dubbla prick-rader med en toppdots-rad (navigation) + fristående stor +-knapp nedtill.
- Njord: +-knappen visas ej med 0 orter (söksektionen är primär CTA); visas alltid vid 1+ orter.
- Njord: fixar iOS-bugg där smooth-scroll i showSearch() förhindrade click-event på sökresultat.
0.5.94
2026-05-11
- Njord: swipe dots now appear both above the forecast (navigation) and below (with + button).
- Njord: add-location button next to bottom dots made larger and more prominent.
0.5.93
2026-05-11
- Njord: const/let in all rendering and statistics functions (appendSummaryDayBlock, computeDayAgreement, mergeSummary*, buildSummaryPrecipLine).
- Njord: search results now have tabindex and role=option/listbox; Enter/Space activates selected result for full keyboard navigation.
0.5.92
2026-05-11
- Njord: var→const/let in all API and utility functions (fetchYr, fetchSmhi, fetchNoaa, fetchOpenMeteo, fetchAll, searchLocation, location/cache helpers).
- Njord: @font-face changed to font-display:optional — if the external brand font is unavailable the system fallback is used immediately without layout shift.
0.5.91
2026-05-11
- Njord: top-level JS constants and DOM refs converted to const/let (module-level var eliminated).
- Njord: loading spinner now pulses with CSS animation; respects prefers-reduced-motion.
0.5.90
2026-05-11
- Njord: show error message instead of perpetual loading spinner when all weather sources fail.
- Njord: /njord/ HTML response now served from in-memory cache (invalidates on deploy); fixed mimetype assignment.
0.5.89
2026-05-11
- Njord: reverse geocoding for GPS now uses Nominatim (was Open-Meteo search — broken for coordinates); added User-Agent header to YR.no calls per their ToS.
- Njord: service worker no longer gets no-store cache header (fixes iOS Safari SW registration); 10 s fetch timeout on all API calls; GPS errors shown inline instead of alert().
- Njord: language toggle now re-renders from cache instead of re-fetching all forecasts; location dots show place names in aria-labels.
- Njord: added route tests for /njord/, sw.js, manifest and path-traversal protection.
0.5.88
2026-05-10
- Njord: standalone weather PWA at /njord/ (renamed from Weather) — 10-day forecast comparison from YR.no, SMHI, Open-Meteo, and NOAA with swipeable saved locations, dark/light theme, and EN/SV toggle.
- Njord: NOAA as fourth forecast source for US locations (auto-detected); SMHI uses snow1g/v1 API.
0.5.87
2026-05-06
- Hopper: equipment setup replaced with a step-by-step yes/no wizard — one question per piece of kit with a short explanation, progress dots, and Ja/Nej buttons.
0.5.86
2026-05-01
- Hopper + Gota: 30-min+ 'For Time' sessions now generate two separate race blocks with different movements and 2 min rest between — shorter sessions keep the single-block format.
- Hopper + Gota: box jumps can no longer be paired with leg-fatiguing movements (lunges, air squats, box step-ups) to reduce injury risk.
0.5.85
2026-04-30
- Hopper + Gota: install banner now appears at the top of the page in browser mode — tap 'Install' to add to home screen, or 'Not now' to dismiss (remembered per device).
- Hopper: faint lion watermark now appears in the lower portion of the screen background.
- Gota: faint blue logo watermark now appears in the lower portion of the screen background.
0.5.84
2026-04-30
- Hopper + Gota: emomFactor speed scaling now applies to all per-move workouts (AMRAP and EMOM), not just EMOM — e.g. 9 jump rope DU becomes 45 DU per round.
- Hopper: AMRAP Mode A now always shows fixed reps per movement — the 50/50 'ladder mode' that showed movement names with no rep counts is removed.
- Hopper: 'For Time' schemes (21-15-9, 50-40-30-20-10, 100-80-60-40-20) are now always single-block Mode A — they can no longer end up as multi-block per-move AMRAP where rep counts are too high to complete even one round.
- Hopper: per-move cycling workouts now always show 'AMRAP' header — 'For Time' was contradictory when the format is 'do the movements in order, start over'.
- Hopper: warmup (~2 min) + transition (1 min) = 3 min are now always deducted from schedulable time — a 15 min session gives at most 12 min of actual work blocks.
- Hopper: rest caps now tiered by work block length — ≤3 min work → 1 min rest, ~4 min work → 2 min rest, 5–7 min work → 3 min rest.
0.5.83
2026-04-30
- Hopper + Gota: AMRAP/For Time header now shows actual work minutes after warmup deduction — a 15 min session shows 'AMRAP 12 min', not 'AMRAP 15 min'.
- Gota: all workout generation fixes ported from Hopper — warmup/transition deduction, rest tiering, for_time→Mode A, jump-cardio filter, AMRAP always per-move, timerExtra placement, no bullet asterisks.
- Hopper: EMOM reps now scaled by movement speed via per-movement emomFactor — jumping jacks/mountain climbers get ×5 (30–50 reps), air squats/sit-ups/lunges/KB swings/push-ups get ×2, deadlifts get ×1.5. Burpees and box jumps unchanged.
- Hopper: EMOM block count is now always divisible by the number of movements — e.g. EMOM-10 with 3 movements becomes EMOM 9 min so the session ends on the last movement.
- Hopper: EMOM interval info ('9 × 60 s · no rest between minutes') now appears directly under the EMOM header instead of at the bottom of the workout.
0.5.82
2026-04-30
- Hopper: round/rest info ('3 rounds · 3 min work · 3 min rest') now appears directly under the AMRAP/For Time header instead of after the movement list.
- Hopper: removed bullet asterisk (*) from warmup and movement lines in workout output — numbers now appear directly without a leading *.
- Hopper: AMRAP time cap now correctly subtracts the 2-minute warm-up buffer so a 30-min session generates AMRAP ~28 min instead of the full 30.
- Hopper: jump rope (DU), jumping jacks, and box jumps can no longer appear together in the same workout — at most one jump-cardio movement per session.
0.5.81
2026-04-29
- Hopper: buttons and time-selection chips now use FM Stencil (same as the Hopper logo).
- Hopper BRAK: portrait splash added — animated rotate-device icon with 'Vänd telefonen' / 'Rotate device' shown when phone is held upright; disappears automatically when rotated to landscape.
- Hopper BRAK: no duplicate movement picks in generated BRAK rounds (deduped warm-up/strength pools). BRAK team timer UI in landscape now prioritizes exercise readability, uses smaller WORK/REST chips, hides non-interval modes in settings, and Reset restarts the fixed 10-round 45/15 BRAK flow instead of clearing to zero.
- Hopper PWA update flow hardened: service worker registration now uses a versioned URL plus updateViaCache=none and immediate reg.update() so clients pick up fresh deploys more reliably.
- Hopper BRAK team timer: phase labels now stay uppercase in landscape/horizontal mode (WORK/REST and ARBETE/VILA), and Swedish done label is standardized to KLAR.
- Hopper timer UI: landscape/low-height view now uses a denser bottom bar with less wasted space, larger exercise text, and clearer phase/clock sizing. Rest line now shows upcoming block as 'Upcoming: ...' / 'Kommande: ...'. End-state phase label is now uppercase DONE / KLAR.
- Hopper BRAK: fixed timer config — rounds now correctly pre-set to 10 via URL params (gym_timer.js was overriding the inline pre-config with its own default of 3). Removed duplicate BRAK team button and BRAK title text from the timer page.
- Hopper BRAK: during rest intervals the exercise banner now shows the upcoming exercise name instead of the one just completed.
- Hopper: BRAK team button — opens a fullscreen interval timer (VITAIL gym_timer) pre-configured with 10 rounds, 45 s work / 15 s rest, 10 s countdown. Alternates warm-up and strength exercises from the BRAK pool; exercise name shown prominently above the digits. Landscape mode supported via gym_timer.css.
- Hopper: BRAK reformatted as 45 s warm-up / 45 s strength / 15 s rest interval circuit. Picks 1 exercise from a warm-up pool (arm circles, inchworms, air squats, scapular push-ups, shoulder rolls, toy soldiers, plank to toe touch) and 1 from a strength pool (duck walk, bear walk, jumping jacks, air squats, sit-ups, lunges, mountain climbers, push-ups, burpees). Timer runs 6 pairs × 45+45+15 s ≈ 10 min. Explain panel shows coaching notes for the two chosen exercises.
- Hopper: BRAK button added — 10-min bodyweight circuit to activate circulation. No warm-up section; designed as a quick wake-up for cold or tired soldiers.
- Hopper + Gota: two new warm-up exercises added — Toy soldiers (triggered by box jumps, box step-ups, and running) and Plank to diagonal toe touch (triggered by push-ups, burpees, bear walk, and duck walk). Both include EN + SV coaching notes in the help/explain panel.
0.5.80
2026-04-28
- Hopper + Gota: EMOM workouts now show explicit minute-by-minute format with rep counts (e.g. Minut 1: 6 Box jumps, Minut 2: 8 Push-ups, etc.) and rest stations. Format clearly shows station count and repeat count (e.g. → Upprepa 3 varv).
- Hopper + Gota: AMRAP instructions simplified to 'Do the movements in order. When done, start over.' and 'Gör övningarna i ordning. När klar börja om.' (SV) for clarity.
- Hopper + Gota: EMOM instructions removed in favour of self-explanatory minute-by-minute format.
- Hopper + Gota: movement rep counts now displayed inline (e.g. '5 Burpees') instead of as bullet list.
- Hopper + Gota: burpees and push-ups are now blocked from ladder-mode for-time WODs when the total reps per movement would exceed 100 (e.g. 50-40-30-20-10 and 100-80-60-40-20 schemes). Per-move format and AMRAP schemes are unaffected.
- Hopper + Gota: all volume and doability limits (rep caps, time-fill fractions, distance limits, session-length thresholds) extracted into a named constant block for easy tuning.
- Hopper + Gota: EMOM sessions with multiple rounds now use one of two distinct formats — 4-station EMOM (3 movements + 1 built-in rest station per cycle, e.g. rest at min 4, 8, 12 …) or multi-round EMOM (N × EMOM-K with 3 min between rounds, rest info shown in header). The two formats no longer share prescription text, removing the previous confusion where the body text implied a continuous EMOM but a footer note revealed a hidden rest break.
0.5.79
2026-04-27
- Hopper: new intro on first visit (language choice) and again after a week away or from the gear — typewriter text in a compact pass-style card over a light dim, primary 'Skip to settings' / 'Till installningar' button (same weight as New workout), tap the text to advance, reduced-motion support, and intro date in localStorage.
- Hopper: opening the gear still shows the intro from the language step if needed; the primary control skips straight to the equipment screen so settings stay reachable.
- Hopper intro: reordered screens (what Hopper is now before the Armed Forces slide), consistent two-space indent on all EN texts, language buttons side by side, auto-scroll during typewriter so the last screen never needs manual scrolling, thin 3 px accent-coloured scrollbar, feedback email clickable in brand orange.
- Hopper intro: fixed Swedish phrasing on splash screen 3 (Du anger vilken utrustning / hur lang tid).
- Hopper intro: removed the 'no kudos / no streaks' screen; easy mode line now points to settings; last screen rewritten (tracking note at the end, email in orange).
- Hopper intro: backdrop blur + stronger dim behind the splash overlay; panel now has card background, border and shadow so it reads cleanly over the dimmed app.
- Hopper intro: feedback email moved to its own final screen (screen 7).
- Hopper intro: removed hardcoded mid-sentence line breaks from all splash screens — text now wraps naturally to viewport width.
- Hopper: warm-up exercises now appear in Help (movements section) and in the workout explain panel, each with a short technique note in EN and SV.
- Hopper: multi-round EMOM -- session time is now filled with N rounds of EMOM-K and 3 min rests between rounds.
- Hopper + Gota: timer scheduling info moved to bottom of prescription; double unders minimum 9 reps; push-ups capped at 10 reps per round; feasibility check always-on; Gota gets warmup guide, explain panel warmup, multi-round EMOM, and all recent Hopper improvements.
0.5.78
2026-04-22
- Hopper: during single-block workouts (solo 5 km or a Mode A ladder) the timer sub-line now shows just the scheme name instead of the awkward 'Block 1 / 1' label.
- Hopper: movements.json now times out after 8 seconds on a stalled network so the welcome screen no longer hangs silently; the PWA service worker also auto-reloads the page once it takes control so you see the latest version right after a deploy.
- Hopper (internal): new 95-test deterministic unit suite for pure helpers (formatting, rep math, scheme eligibility, pool filters, feel-bias, warm-up text, solo_5k output) plus pytest coverage for PNG icons and the nosleep.js fallback. All tests run on every push.
0.5.77
2026-04-22
- Hopper: each workout now opens with a short adaptive warm-up (about 2 minutes) tailored to the movements you drew. The timer still only counts the work itself.
- Hopper: countdown beeps 3-2-1-GO before every work and rest block, plus a half-way cue for longer work intervals so you know when you're at the halfway mark.
- Hopper: new EMOM formats (every minute on the minute) — EMOM-10 and EMOM-12 rotate through your drawn moves one minute at a time.
- Hopper: Copy-text button next to Save-image so you can share the workout straight into chat or notes.
- Hopper: after the timer runs out, a quick Too hard / Just right / Too easy tap logs how the session felt; two 'too hard' sessions in a row automatically pull the next workout toward the easier pool.
- Hopper: installable as a home-screen app on iOS and Android — works offline after the first visit (new manifest, service worker, and dedicated 192 / 512 px icons).
- Hopper: iOS Safari screens no longer dim mid-workout — a silent-video fallback keeps the screen awake on older iPhones that lack the modern Wake Lock API.
- Hopper: the 'Too easy / too hard' cool-down block has been removed — it was noise most users skipped. Warm-up stays because it's on the action path.
0.5.76
2026-04-22
- Hopper: duck walk and bear walk are excluded from Mode A AMRAP schemes — they cap at the same distance every round, making the ladder look identical at every step.
- Hopper: For Time workouts now require an estimated time between 35 % and 90 % of the session length, preventing workouts that are far too short or too long for the chosen duration.
- Hopper: push-ups and burpees are excluded from AMRAP schemes whose highest rep step exceeds 9 — high rep sets cause intensity loss in continuous AMRAP format.
0.5.75
2026-04-21
- Longevity · bodyweight: program copy and docs now match the rolling 3-day A/B/C rotation and per-day tier rules (8-week overview is a timeline, not six separate pattern days).
- Profile & welcome: if menopause is post, menstrual cycle tracking is turned off (server-side) and the cycle UI is hidden with a short explanation.
- Welcome (female): menopause is chosen with radio buttons and short explanations (pre/peri/post); cycle tracking notes that Today’s phase shapes only that day’s plan (no diary stored).
- Workout: Longevity · bodyweight no longer opens the barbell max-lift PR modal or the provisional-weight hint (calisthenics users are not nudged toward bar/plate tests).
- Workout: the per-lift PR reminder only appears when the session’s main lift maps to a barbell max on My Records (squat, bench, deadlift, OHP) — not for calisthenics names like push-ups.
- Admin → Users: last sign-in times are shown in Swedish local time (Europe/Stockholm).
- Admin → Users: sort every column (email, plan, sex, age, last sign-in) and filter by email text, goal, sex, age range, and last sign-in date range (server-side, pagination preserved).
- Endurance: removed the separate trail-run modality — long trail distances are entered under Running, and saved trail times are merged into running automatically.
- My Records: all discipline sections and strength lifts start collapsed (no auto-open on profile focus).
- Onboarding: if you select female, you now set menopause phase and optional cycle tracking before leaving step 1.
- Beta: default account cap is 40 sign-ups when BETA_MAX_USERS is unset; set BETA_MAX_USERS=0 for unlimited registration.
- Conditioning (erg): bike distances in workout text are the reference; SkiErg and row show ~50 % metres. Fixed duplicate halving and lowercase bike/ski/row labelling for your preferred machine.
- Workout block timers: Prep now has the same tap-to-start timer (uses the estimated prep time when available). Blocks that spell out rounds plus work and rest durations (e.g. four rounds, three minutes work, one minute rest) get an interval countdown instead of a naive count-up; every start still begins with the 10 s get-ready countdown.
- Workout: main-lift set timer matches block-timer layout (time + controls on one row); the 10 s get-ready runs only once when you first start the timer, not between rests; a short hint explains that the chip counts rest between sets while the tile header minutes are a full-block estimate.
- Today’s primary-block minute estimates for calisthenics (longevity bodyweight) are tightened so they better match short sessions; rest timers still show the programmed rest between sets (e.g. 3:00), not the whole block.
- Workout header: for Longevity · bodyweight / calisthenics, the profile line no longer repeats the goal twice (drops the redundant “Longevity bodyweight” protocol label when the track already says bodyweight).
- Workout: session context (goal, structure, time, failure policy, notes) is merged into one collapsed “About this session” block with a one-line teaser; repeated time-budget phrasing is not duplicated in the notes line when minutes are already shown under structure.
0.5.74
2026-04-20
- Bodyweight / calisthenics track rewrite: the programme now runs a rolling 3-day A/B/C rotation (Day A: Push, Day B: Pull + Hinge, Day C: Squat + Skill) instead of the old 6-pattern system.
- Every session includes bear walk in the mobility warm-up. Day B adds a dedicated hinge complement block.
- Conditioning block scales with available time: 2 rounds at 30 min, 3 at 45 min, 4 at 60+ min. Movements rotate through a per-day pool and adapt to your equipment.
- New profile and onboarding question: available equipment (pull-up bar, resistance band, jump rope, parallettes, box/chair, running). Exercises adapt automatically when gear is missing.
- Each strength tier now shows an exit criterion so you know exactly when you're ready to progress.
0.5.73
2026-04-20
- New profile field: preferred erg machine (Bike / Ski erg / Row). Bike conditioning distances stay full; ski/row distances are halved to reflect real effort equivalence.
- Primary strength tile now shows the lift name directly above the spec bar, so you don't have to scroll up to see which lift you're working.
0.5.72
2026-04-20
- Block timer now uses the stated time cap (e.g. 'Time cap: 14 min') as the target duration, taking priority over AMRAP or general time estimates.
0.5.71
2026-04-20
- 5×5, GVT, and linear tracks now use the same per-set rest timer as Wendler — consistent timer behavior across all strength protocols.
0.5.70
2026-04-19
- Block timers now auto-detect AMRAP and timed blocks (e.g. 'AMRAP 12 min', '10 min') and count up to that duration, then stop with a 'Time!' display. Audio beeps at 3-2-1 during get-ready, a longer Go beep at start, and a done beep at finish.
0.5.69
2026-04-18
- Tap-to-start count-up timer added to the Secondary, Accessory, and Aerobic workout blocks — enable it under Profile. Includes a 10 s get-ready countdown before each block. For mixed-metcon sessions with a short WOD, the aerobic timer pre-seeds the timecap so you can see when you go over.
0.5.68
2026-04-18
- Swedish users now see workout instructions in Swedish: all session coaching notes, goal axis lines, aerobic blocks, secondary exercises, Hyrox station blocks, and metcon descriptions are fully translated.
- All hardcoded English aria-labels and title attributes in templates are now localised (workout time-budget pill, nav landmark, vote buttons, changelog link).
- Remove "prototype" from the site footer — the app is in production.
0.5.67
2026-04-18
- Fix workout page screen lock: the screen no longer stays dark after switching tabs or locking the phone mid-session — the wake lock is now reacquired whenever the workout page becomes visible again.
0.5.66
2026-04-18
- Make Wendler 5/3/1 deload week optional: after the last heavy session (week 3), user can choose to run the deload week as usual or skip it and restart the cycle with bumped training maxes immediately.
0.5.65
2026-04-18
- Add opt-in per-set rest timer on workout page (profile setting `workout_timer_enabled`, default off; shows prestart +10s, countdown, pause/resume, auto-hides when done).
0.5.64
2026-04-17
- **CrossFit benchmark library** — 61 named WODs (Girls, Heroes, AMRAPs, Open workouts) now live in the conditioning pool with muscle-group conflict filtering, kg/lb loads, and scaled variants. Mixed metcon track picks a fitting benchmark daily; HSPU/muscle-up/pistol workouts filtered out for wider accessibility.
0.5.63
2026-04-15
- **Conditioning engine** — Smart workout picker that selects complementary conditioning based on today's barbell lift. 50+ original workouts in two pools (erg intervals + strength-metcon). Muscle-group conflict filter prevents doubling up — no thrusters after squats, no push-ups after bench.
0.5.62
2026-04-14
- **Auto-progression** — 5×5, Linear 3×5, and GVT now automatically bump your working weight after each session when you trained fresh/stable and cadence allows (7 days if under 40, 14 days if 40+).
0.5.61
2026-04-10
- **5×5 intensity** — Raised from ~74% to ~81% of 1RM, matching standard straight-set 5×5 literature.
0.5.60
2026-04-10
- **GVT rest periods** — Changed from E3M (3 min) to E90s (90 sec) matching Poliquin's original protocol.
- **GVT intensity** — Raised from 55% to 60% of 1RM (standard GVT load = your 20RM).
- **GVT tempo** — Added 4-0-2 tempo prescription to coaching text and intensity display.
- **GVT coaching** — Rewritten beginner and Rx coaching text (EN + SV) with correct rest, tempo, and intensity.
0.5.59
2026-04-10
- **Profile: experience gates programs** — Beginners: Linear 3×5 only. Intermediate: Linear, 5×5, 531. Advanced: all incl. GVT.
- **Profile: field reorder** — Experience now comes first (before goal and days), since it determines available programs.
- **Onboarding: same filtering** — Welcome wizard shows only programs matching selected experience level.
- **Backend validation** — Server-side clamp prevents invalid experience+program combos even with manual POST.
0.5.58
2026-04-10
- **About page** — Added Linear 3×5, 5×5, and GVT protocol explanations (progression, intensity, fatigue rules).
- **About page** — Contact line now points to the in-app feedback icon instead of an email address.
0.5.57
2026-04-09
- **UX: About page** — Restructured from flat list to 3 logical groups (Training, Body & Recovery, Numbers).
- **UX: About page** — Each section is now collapsible — page is scannable instead of a wall of text.
0.5.56
2026-04-09
- **UX: Workout page — less noise** — Hero identity chips (goal/level/protocol) compressed to a single muted line.
- **UX: Workout page** — Duplicate lift name removed from Primary tile (already shown in hero headline).
- **UX: Workout page** — Duplicate goal/protocol pills removed from Context details section.
- **UX: Workout page** — Prep and Recovery sections are now collapsible (closed by default, open for beginners).
0.5.55
2026-04-09
- **UX: Login page** — added value proposition subtitle and clearer "Switch server" label (was "NW").
- **UX: Register form** — logo shrinks when registering so the full form (disclaimer + button) fits without clipping.
- **UX: Today page** — added visible "Daily check-in" heading.
- **UX: Workout page** — empty blocks (secondary, accessory, aerobic) are now hidden instead of showing "(omitted)".
- **UX: Workout log** — dates are grouped as sub-headers within each week instead of repeating per row.
- **UX: Profile** — added visual separator between Save and Clear profile buttons.
- **UX: Top controls** — increased spacing between icons for better touch targets.
0.5.54
2026-04-08
- **Error pages:** Custom **404** and **500** error pages with i18n support (EN/SV).
- **Health check:** New `/health` endpoint returns JSON `{status: ok}` with DB ping — for monitoring and orchestration.
- **Session security:** Explicit **7-day session lifetime** (`PERMANENT_SESSION_LIFETIME`); `session.permanent = True` at login/register.
- **Input hardening:** `parse_profile()` no longer crashes on missing `age`/`training_days` form fields — uses safe `.get()` with defaults.
- **Beginner glossary overhaul:** Expanded from 18 to 30+ terms — added DU, HSPU, GHD, Z2, superset, compound, antagonist, unilateral, ROM, GPP, deload, tempo notation (3-0-1-0), grinders. Fixed Swedish OHP translation (militarypress → axelpress).
- **About page:** Added changelog link and contact email to the about page footer.
- **Data export (GDPR):** New `/export` route downloads all your data as JSON — profile, workout logs, and PR history.
0.5.53
2026-04-08
- **Coaching tone:** **`intermediate`** and **`advanced`** use terse **Rx-style** **`primary_coaching`** (**`rx_coaching_*`**) and short barbell **`movement_prep`** / **`recovery_transition`** (**`rx_movement_prep_barbell`**, **`rx_recovery_transition_strength`**). **`beginner`** keeps long **`beginner_coaching_*`**, verbose prep/recovery, and glossary expansion.
0.5.52
2026-04-07
- **Logs redesign:** Workout log entries grouped by **ISO week** — compact single-line rows that expand on tap. Week headers show session count and average effort. Much faster to scan training history.
- **Program overview:** Workout plan page shows **key-value overview** (template, duration, frequency, progress bar) instead of prose paragraphs. Phase cards include **inline week pills** with current-week highlight. Standalone week strip removed.
- **Wendler fix:** Clearing all workout logs now **resets wendler_week to 1** and clears wave state — prevents stale deload trigger after log wipe.
- **PR-only weights:** Working weights always derived from saved **profile PRs** (``pr_*``). Removed dual weight tracking via ``user_progression.weight``. The **/prs** page shows a **cycle-progression badge** when a lift's 1RM was auto-calculated after a Wendler cycle.
- **Changelog rule:** Added **CLAUDE.md** project rules and a **pre-commit hook** that warns when user-facing files change without a changelog update.
0.5.51
2026-03-27
- **Beginner copy:** When **`experience` is `beginner`**, session plans use plain-language **`primary_coaching`** from i18n (**`beginner_coaching_*`**) plus **`simplify_session_text`** (`vitail_session/_simplify.py`) to expand abbreviations (RPE, AMRAP, E3M, zone 2, RDL, etc.) once per string field after injury/time modifiers. **`compute_daily_session(..., locale=...)`** (Today POST passes UI locale). Workout page shows **`workout_badge_e3m_expanded`** instead of raw **E3M** for beginners. Plan preview applies the same rules. Docs: **`VITAIL_Session_Engine.md`**, **`VITAIL_Training_Programs.md`**, **`VITAIL_User_State_Schema.md`**. Tests: **`tests/test_simplify.py`**, **`tests/test_beginner_session_copy.py`**.
0.5.50
2026-03-26
- **Tooling:** Ruff now includes **B** (bugbear), **SIM** (simplify), and **RUF** (excluding ambiguous-Unicode rules **RUF001–003** project-wide so ×/dashes in training copy stay). **SIM** cleanups (e.g. `contextlib.suppress`, merged profile branches) and **RUF** nits (redundant `int()`, unused unpack). **`vitail_web.deployment`:** single **`is_hosted_deployment()`** shared by factory and auth.
0.5.49
2026-03-26
- **Architecture:** Flask routes split into the **`vitail_web`** package: **`auth`** (login, register, welcome, password reset), **`training`** (Today, workout, profile, PRs, logs, program preview, feedback board), and **`admin`** (``/admin/users``). **`web_app.py`** remains the entrypoint (`python web_app.py` / `web_app:app` for Gunicorn). URLs unchanged; template **`url_for`** targets use blueprint endpoints (e.g. **`training.today`**, **`auth.login`**).
0.5.48
2026-03-26
- **Profile:** Removed **race / event** training UI (event text, date, web “Research”) and **`/profile/research-event`**. Saving profile **clears** stored event fields; session builders no longer use event context (DB columns kept for compatibility). Removed **`vitail_goal_research.py`**.
- **i18n / workout:** Dropped unused **event** translation keys and the dormant **event-alignment** tile on the workout page.
0.5.47
2026-03-26
- **Workout copy:** Physiology-driven tweaks (cycle / menopause) set **`bio_adjustments`** on saved plans. **Why today** bullets and the program line can add **today’s sets×reps** when they differ from the enrolled template (e.g. 5×5 chip vs 3×5 prescription). Coaching footnote clarifies that **sets × reps above** are authoritative when bio rules changed volume.
0.5.46
2026-03-26
- **Cleanup:** Removed unused **``get_recent_readiness``** (DB) and **``wendler_week_for_today_post``** — Today POST now uses **``clamp_wendler_week(profile)``** only (no latest-plan / same-day session heuristics). Re-introduce history-driven logic deliberately later if needed.
0.5.45
2026-03-26
- **Workout complete:** Barbell **progression / rotation** (``update_progression``) runs on **every** logged session, not only the **first** of the calendar day — fixes same-day Wendler (and other) multi-session flows repeating the same main lift. **`get_next_lift`** uses **``LIFTS`` order** (Squat → Bench → Deadlift → Overhead Press) when ``last_done`` ties instead of SQLite’s arbitrary row order. Plan preview copy (EN/SV) clarifies app-chosen queue vs user order.
0.5.44
2026-03-26
- **Tests:** **pytest** + **Flask test client** integration tests (auth, welcome, Today → workout, public routes, admin gate) with **isolated temp SQLite**; existing Wendler unit tests unchanged. **`make test`** / **`make install-dev`**; **`requirements-dev.txt`**. **GitHub Actions** workflow runs **``pytest``** on push/PR to **``main``**.
0.5.43
2026-03-26
- **PostgreSQL:** App database connections use a **process-local pool** (``psycopg_pool``) with ``close_returns`` so existing ``conn.close()`` paths return connections to the pool. Optional **``VITAIL_PG_POOL_MIN``** / **``VITAIL_PG_POOL_MAX``** (defaults 1 / 12). **``close_pg_pool``** runs on process exit (``atexit``). Schema init still uses a one-off connection. Requires **``psycopg[pool]``** in dependencies.
0.5.42
2026-03-26
- **Admin:** **/admin/users** lists accounts in **pages of 50** (``ORDER BY id``) with **Previous / Next** and a total count — avoids loading every row for large deployments.
0.5.41
2026-03-26
- **Password reset email:** Uses **default SSL context** for ``SMTP_SSL`` / ``starttls`` (SNI and cert verification). **ASCII subject line.** Resend: **fail fast** if user/password missing; on any send failure, logs a reminder about **verified ``SMTP_FROM``** and the from-address used.
0.5.40
2026-03-26
- **Password reset email:** SMTP supports **implicit TLS on ports 465 and 2465** (Resend), **STARTTLS on any port** when enabled (fixes Resend on port 25), optional **``SMTP_STARTTLS=0``** for plain relays, **``SMTP_TIMEOUT``** (default 30s), and trimmed **``SMTP_PASS``**. Warn in logs if **smtp.resend.com** is used without user/password. **Resend** setup documented in README (``SMTP_USER=resend``, verified **``SMTP_FROM``**). On **production**, a failed or unconfigured send no longer exposes the reset link in the flash message (local dev still shows the link when SMTP is unset).
0.5.39
2026-03-26
- **Welcome wizard:** Step 1 is now **age**, **training days per week**, and **sex**; step 2 is **goal**, experience, and goal-specific program/focus; summary lists demographics first.
0.5.38
2026-03-26
- **Admin:** ``users.admin`` flag (set via SQL). Admins see an **Admin** link under Account in the bottom nav; **/admin/users** lists masked email, plan, sex, age, last sign-in, and **Remove** (cannot remove self). Feedback replies use the same admin flag instead of a hard-coded email.
0.5.37
2026-03-26
- **Accounts:** Each successful **Sign in** updates ``users.last_login_at`` (UTC) and increments ``users.login_count``. No IP stored. New installs and migrated DBs get the columns via ``init_db``.
0.5.36
2026-03-24
- **Welcome wizard:** Step 2 now asks for goal-specific settings — **strength** program (5×5 / 5/3/1 / GVT), **hybrid** flavor, **endurance** primary (+ optional 2nd/3rd discipline), **longevity** barbell vs bodyweight. Summary step shows **Focus**; inactive goal fields are disabled so POST stays clean. Flash on validation error.
0.5.35
2026-03-24
- **Workout hero:** Two-layer header — eyebrow, large headline (primary lift / modality / recovery), identity row (goal · level · program · longevity track when relevant), tinted **today** strip for state + duration; progress line unchanged.
0.5.34
2026-03-24
- **Today:** The four-lift **PR seed** card only shows for profiles that use barbell maxes (**strength**, **hybrid**, **longevity** with barbell track). **Endurance** users without primary-discipline times see a **nudge** to My Records instead; **longevity bodyweight** no longer gets the lift seed. **`POST /today/pr-seed`** is ignored when the profile should not use strength seed.
0.5.33
2026-03-24
- **Wendler 5/3/1:** `wendler_week` advances only after all four main lifts (Squat, Bench, Deadlift, OHP) are completed in the current meso week, in any order — not once per calendar day. Profile stores **`wendler_wave_state_json`**; Today POST no longer double-advances from a completed 531 row. Undo restores wave state.
0.5.32
2026-03-20
- Removed the top-bar **Add to home screen** control (Material `add_to_home_screen`); manifest / icons / service worker unchanged so manual install from the browser remains possible. `pwa.js` now only handles the help tooltip; static cache bumped to **v6**.
0.5.31
2026-03-20
- **Longevity bodyweight track (full):** Profile field **`longevity_track`** (`barbell` or `bodyweight`) + persisted **`longevity_bw_progress_json`** (rotation & per-pattern tiers). `vitail_bodyweight` builds daily sessions; `compute_daily_session` returns protocol **`bodyweight`** (skips barbell rotation). Completion advances progression; deleting the log restores prior JSON via the same undo mechanism as Wendler/meso. Workout plan overview, time-budget pass, program header line, EN/SV copy, and schema docs updated.
0.5.30
2026-03-22
- PWA / Add to Home Screen icons: **light plate** (`#EEECF8`) with **thicker, higher-contrast** mark so the app reads on dark wallpapers (iOS home screen). Regenerated `icon-192.png`, `icon-512.png`, `apple-touch-icon.png` from updated `vitail-logo-app.svg` / `scripts/build_app_icons_from_symbol.py`; `manifest.json` `background_color` aligned.
0.5.29
2026-03-22
- Primary goal **`hybrid`** is labeled **Functional** (EN) / **Funktionell** (SV); the stored value stays `hybrid`. Program flavor **`crossfit`** becomes **`mixed_metcon`** (DB migration + normalization on load/save). Legacy form values `crossfit` / `wod` / `cf` still map to the same behavior. User-facing copy avoids third-party trademarks; rotating benchmark metcons and Wendler barbell template for that track are unchanged.
0.5.28
2026-03-22
- Removed **Tactical** as a primary goal (unclear in product). Profiles with `goal=tactical` migrate to **`hybrid`** (UI: Functional) on DB init; forms and loads coerce the same. CLI goal menu updated. Workout Plan copy for tactical phases removed; longevity overview notes a planned **bodyweight** track under the same goal (docs + i18n roadmap).
0.5.27
2026-03-22
- Workout log (/logs): delete restores saved state when possible — on complete, the app stores an undo snapshot (user_progression for that lift, Wendler week, running meso week). Deleting the log entry applies it then removes the row. Older log rows without a snapshot are only removed from the list.
0.5.26
2026-03-22
- PWA: service worker at /sw.js precaches same-origin /static assets (CSS, JS, icons, manifest) and serves them from cache when offline or slow; bump CACHE_VERSION in static/vitail-sw.js when changing cached files.
0.5.25
2026-03-22
- Today check-in: time available (30–90 min) is parsed from the form and passed into session generation (previously ignored on submit). Endurance plans now run the same time-budget pass as strength (rationale tag + estimated duration / block times).
0.5.24
2026-03-22
- Profile injury/limitation notes are always woven into generated session plans (rationale, failure policy, prep, primary and supporting blocks) and shown in a prominent banner on the workout page from the live profile (EN/SV).
0.5.23
2026-03-22
- Feedback page (/requests): same form for feature ideas and bug reports; optional type (feature / bug), stored and shown as a badge; copy and nav label updated (EN/SV).
0.5.22
2026-03-22
- Timer: large settings (gear) button always visible — portrait scrolls to controls, landscape toggles sheet; larger tune control in landscape; EN/SV aria labels.
0.5.21
2026-03-22
- PostgreSQL (e.g. Railway): on init, try CREATE EXTENSION pg_stat_statements so platform query-stats UI stops logging “relation does not exist” (ignored if the role lacks permission).
0.5.20
2026-03-22
- Feature requests: normalize created_at to strings for PostgreSQL (fixes /requests 500 when slicing dates in the template). Docker: run with Gunicorn instead of flask dev server.
0.5.19
2026-03-22
- PWA: fix Add to Home Screen on iPhone — tapping the icon no longer immediately closed the instruction bubble (clicks targeted the inner span). Show the install hint on all iOS browsers (not only Safari). Clearer Share / Add to Home Screen copy.
0.5.18
2026-03-22
- Feature requests (/requests): fix internal server error — ensure DB migration runs on each load, rewrite vote aggregation with a subquery (PostgreSQL/SQLite-safe), and broaden areas_json column detection to any schema on search_path.
0.5.17
2026-03-22
- Workout log: fix crash for Wendler sessions (work sets use kg, not weight) and for secondary/aerobic stored as lists or objects. Feature requests: optional multi-select areas including aerobic (and Today, workout blocks, log, My Records, etc.), stored and shown as tags.
0.5.16
2026-03-22
- Workout: short “Why today’s plan” card from Today check-in; enrolled-program progress line; link to Timer with URL presets (interval/rest matched to primary work). My Records: modalities in collapsible sections, vertical distance rows (no horizontal scroll), “Previous best” under strength and endurance fields. Copy aligned with Workout log / My Records; Today controls use tap-friendly min height.
0.5.15
2026-03-21
- Security: on hosted deploys (FLASK_ENV=production or Railway production), the app refuses to start without SECRET_KEY or FLASK_SECRET_KEY. Event-goal research API (/profile/research-event) now requires a signed-in user; it stays available during profile onboarding.
0.5.14
2026-03-21
- UI polish: Inter font weights 300–600, antialiased body text, shared design tokens (--radius-*, --text-muted). Database module uses a single open_connection() entry point; PostgreSQL placeholder helper is adapt_sql (alias of internal _q).
0.5.13
2026-03-21
- Registration requires accepting a health & liability disclaimer (own risk, not medical advice, limitation of liability). Feature Requests (/requests) is login-only; guests are redirected to sign in.
0.5.12
2026-03-21
- Optional beta registration gate: set BETA_MAX_USERS (e.g. 10) to cap accounts, and BETA_INVITE_CODE or BETA_INVITE_CODE_HASH (SHA-256 hex) so new sign-ups need a shared invite. Unset env vars = unchanged open registration.
0.5.11
2026-03-21
- Gym timer: in landscape orientation, the control sheet closes automatically when you press Start so the digits stay full-screen while the session runs.
0.5.10
2026-03-21
- Gym timer sounds reworked: sine waves with attack/release envelopes and light low-pass filtering (less clicky than square-wave pings). Slightly retuned frequencies for armed / countdown / GO.
0.5.9
2026-03-21
- Gym timer: Web Audio beeps — short armed tone on Start; during +10s pre-start, beeps on 3-2-1 and a double GO at zero. Interval and EMOM modes use the same 3-2-1 + GO at each phase / round boundary. Sound toggle below +10s (default on).
0.5.8
2026-03-21
- Added Feature Requests page (/requests) — a lightbulb icon in the top controls opens a public board where logged-in users can submit ideas and everyone can browse them. Email addresses are masked (first 2 characters visible, rest hidden).
0.5.7
2026-03-21
- Added Workout Log page (/logs) under the Account menu. Shows all completed sessions with primary lift, secondary work, aerobic block, readiness signals (sleep/hydration/fatigue), perceived effort rating, and session notes.
0.5.6
2026-03-21
- Sleep input changed from a numeric hours slider to a simple Poor / OK / Good selector, consistent with the hydration field. Session state logic updated accordingly.
0.5.5
2026-03-21
- Extended database to track user-executed workouts: added session_sets table for per-set logging (weight, reps, RPE, distance, pick-one choice) and pr_history table for longitudinal PR trending.
- Daily readiness check-in (sleep, hydration, fatigue, cycle phase, time available) is now stored alongside each session for rolling fatigue analysis.
- Post-session feedback added to workout completion: perceived effort rating (1–5 with emoji) and a free-text session note.
- Profile enriched with four new fields: body weight (kg), equipment available (full gym / dumbbells / bodyweight / home), event date, and injury/limitation notes.
- PR saves now automatically append a snapshot to pr_history for both strength lifts and endurance times.
0.5.4
2026-03-21
- Replaced all custom SVG and emoji icons with Material Symbols (Google's Material Design icon library). Covers top controls (info, install, theme) and the nav bar (today, workout, timer, account).
0.5.3
2026-03-21
- Login and register merged into a single tabbed page — Sign In / Register tabs, no redirect bounce. Register errors stay on the register tab with email pre-filled.
0.5.2
2026-03-21
- Added N/A as a third sex option on the profile page. Menopause/cycle-tracking fields remain female-only.
0.5.1
2026-03-21
- Field-level encryption for sensitive profile data (sex, menopause status, event goal summary) using AES-128 Fernet. Requires VITAIL_ENCRYPT_KEY env var; degrades gracefully to plaintext if unset.
- Updated 'About VITAIL' tooltip to accurately reflect data storage (server-side, encrypted, no analytics).
0.5.0
2026-03-21
- UI redesign: premium light-mode palette aligned with brand colors (accent #534AB7, text #1A1A2E).
- Top controls converted from separate floating buttons to a single grouped pill toolbar.
- Version badge moved from fixed top-left to footer alongside copyright.
- Navigation: borderless tiles with SVG icons above labels; active tab is a filled purple pill.
- Account tab chevron replaced with a person icon.
- User info shown in a card with accent left border; 'Sign out' styled as a ghost button.
- Cards: 16px border-radius, soft shadow in light mode (no hard border).
- Tagline clamped to 2 lines with max-width 260px to prevent single-word wrapping on mobile.
- Horizontal padding increased to 24px throughout; section spacing increased to 32px.
- Inter loaded as primary UI font.
0.4.4
2026-03-21
- Brand assets integrated: SVG favicon (symbol), app icons regenerated from real logo, Inter 300 loaded for wordmark rendering.
- Header wordmark replaced with branded 'vitail' logotype — 'vit' and 'l' in theme-adaptive text color, 'ai' in brand orange (#FF6B00), font-weight 300.
- Manifest theme_color updated to brand purple (#534AB7).
0.4.3
2026-03-21
- Added PWA support: manifest, app icons, and iOS meta tags so VITAIL can be installed to the home screen on any device.
- Added 'Add to Home Screen' install button next to the language flags: shows the native install prompt on Android/Chrome, and a Safari share-sheet instruction on iOS.
- Mobile layout audit: fixed header padding to clear the expanded top-bar, added narrow-screen (≤400px) breakpoint so all four controls fit cleanly on iPhone SE.
0.4.2
2026-03-21
- Added forgot-password flow: request a reset link by email, then set a new password via a secure one-time token (expires in 1 hour).
- When no SMTP server is configured (local dev), the reset link is printed to the server log and shown as a dev-mode flash message.
0.4.1
2026-03-21
- Fixed: progression table no longer corrupted when doing a one-off session under a different program (e.g. Wendler user doing a Functional pass). Lift rotation still advances correctly, but weight and progression timestamp are protected unless the session protocol matches the user's current profile.
0.4.0
2026-03-21
- Workout now realistically fits your chosen time budget.
- Time tier logic corrected: 45 min removes both secondary and accessory (previously only accessory); 60 min removes accessory (previously nothing was removed).
- Mixed-metcon benchmark workouts filtered by available time — e.g. 45 min budget only picks shorter benchmarks (Fran, Grace, Annie, etc.); Murph/Eva/Chelsea reserved for 75–90 min sessions.
- Each workout tile now shows an estimated duration (~X min), and the session hero shows total estimated time with a color-coded warning if it exceeds your budget.
- Metcon estimates shown inline (e.g. named benchmark ~10 min).
0.3.9
2026-03-21
- Fixed: 'No saved max for Bench Press' modal appearing even after saving a bench PR. The modal now checks the live profile instead of the stored session flag.
- Saving PRs now invalidates the current draft session so the next workout is regenerated with the correct working weights.
0.3.8
2026-03-21
- Time input fields now accept plain minutes — typing '28' is interpreted as 28:00, '28.5' as 28:30. mm:ss and h:mm:ss still work as before.
- Improved error message when a time value can't be parsed.
0.3.7
2026-03-21
- Hybrid / functional programs now meaningfully distinct: Hyrox, mixed metcon, and balanced GPP each have a unique prep, secondary, accessory, and conditioning block.
- Mixed metcon track: named benchmark workouts rotate daily — Annie, Helen, DT, Fran, Grace, Cindy, Murph, and 13 others. Today's pick is shown in the aerobic tile.
- Hyrox track: dedicated station block (wall ball, sled push, sandbag lunges, burpee broad jumps) + specific running/erg engine intervals.
- Balanced GPP track: unilateral accessories, loaded carry superset, broad mixed-modal finisher at conversational effort.
0.3.6
2026-03-21
- BikeErg PR distances updated to standard Concept2 test distances: 500m, 1k, 2k, 5k, 10k, 20k.
0.3.5
2026-03-21
- Endurance Engine: endurance goal users now get a proper endurance-primary session (Zone 2 / tempo / intervals / absorb) instead of a barbell session with endurance notes bolted on.
- Endurance primary rotates through a 4-week meso cycle: base (Z2), build (tempo/threshold), quality (intervals), absorb (recovery).
- Strength maintenance secondary block preserved for endurance users — low volume, no leg grinders.
- Event research UI: enter a race name on the profile page and click Research to auto-fill event details via web search (+ AI summary when OPENAI_API_KEY is set).
- Event parsing extracted into vitail_event.py (internal refactor — no behaviour change).
- Changelog page added; version badge in top-left is now a link to it.
0.3.4
2026-03-21
- Changelog page — this view, accessible from the version badge top-left.
0.3.3
2026-03-21
- Endurance onboarding: first profile save redirects straight to My Records for pace calibration.
- My Records: strength section collapsed by default for endurance users; endurance times shown first with primary discipline highlighted.
- Workout PR splash: endurance users see a discipline-specific time-trial guide instead of the barbell starting-weight prompt.
- Language switcher: English (🇬🇧) and Swedish (🇸🇪) flags added to the top bar.
- Full Swedish translation across all pages and flash messages.
- Endurance focus selection on profile: choose primary, optional secondary, and optional tertiary discipline (running, cycling, SkiErg, etc.).
- Session hints and goal-axis text now reflect the chosen endurance discipline order.
0.3.2
2026-02-01
- Endurance PR grid: enter best times per distance; app derives pace per km or /500 m split.
- Time-budget bar on Today check-in; meso-week counter.
- Delete account flow with full data wipe.
- PR form hardening: better validation and error messages.
- Fix: init_db now runs before every auth and profile DB operation.
- Fix: login next-URL guard prevents open-redirect abuse.
- Deploy: VITAIL_APP_VERSION env override; git SHA baked into Docker image.
0.3.1
2025-12-10
- Running / endurance goal with pace-aware session extras.
- Welcome splash and profile-first onboarding for new users.
- Show / hide password toggle on login and register.
- Fix: sessions behind reverse proxy (ProxyFix, Secure cookies, SameSite=None).
- Fix: configurable SQLite path for containerised deployments.
0.3.0
2025-10-18
- Draft workout flow: generate, review, and mark complete — progression and history update on completion.
- Workout history: last 8 sessions shown on the Workout page.
- Gym timer: count-up, countdown, E×M, and interval modes.
- Hybrid strength programs added (GVT 10×10, Classic 5×5).
- Dockerfile for container deployment (Gunicorn, $PORT).
0.2.0
2025-08-05
- Full Flask web app replacing the CLI prototype.
- Today check-in: sleep, stress, soreness, and energy sliders feed the readiness model.
- Max-lift entry and bar-maths for Squat, Bench, Deadlift, OHP.
- Wendler 5/3/1 progression with auto-advancing meso weeks.
- Dark / light theme toggle persisted in localStorage.
0.1.0
2025-06-01
- Initial VITAIL physiological decision engine.
- Readiness model from sleep, HRV-proxy, stress, and soreness inputs.
- Session-state machine: fresh → normal → fatigued → overreached → deload.
- SQLite persistence for profile, progression, and session history.
- Linear 3×5 and basic periodisation logic.