From aed407e2d0a963f46e961bb4c46cfd436ec464a4 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Fri, 14 Feb 2025 12:14:45 +0100
Subject: [PATCH 1/7] logger and launch cleanup

---
 .vscode/launch.json                    | 5 ++++-
 frontend/android/settings.gradle       | 2 +-
 frontend/lib/modules/new_trip_map.dart | 1 -
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/.vscode/launch.json b/.vscode/launch.json
index 6f1ce86..fa7d5d9 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -36,7 +36,10 @@
             "type": "dart",
             "request": "launch",
             "program": "lib/main.dart",
-            "cwd": "${workspaceFolder}/frontend"
+            "cwd": "${workspaceFolder}/frontend",
+            "env": {
+                "GOOGLE_MAPS_API_KEY": "testing"
+            }
         },
         {
             "name": "Frontend - profile",
diff --git a/frontend/android/settings.gradle b/frontend/android/settings.gradle
index c9fb5ba..8db313d 100644
--- a/frontend/android/settings.gradle
+++ b/frontend/android/settings.gradle
@@ -19,7 +19,7 @@ pluginManagement {
 
 plugins {
     id "dev.flutter.flutter-plugin-loader" version "1.0.0"
-    id "com.android.application" version "7.3.0" apply false
+    id "com.android.application" version "8.1.0" apply false
     id "org.jetbrains.kotlin.android" version "2.0.20" apply false
 }
 
diff --git a/frontend/lib/modules/new_trip_map.dart b/frontend/lib/modules/new_trip_map.dart
index deb7078..02d4174 100644
--- a/frontend/lib/modules/new_trip_map.dart
+++ b/frontend/lib/modules/new_trip_map.dart
@@ -30,7 +30,6 @@ class _NewTripMapState extends State<NewTripMap> {
   final Set<Marker> _markers = <Marker>{};
 
   _onLongPress(LatLng location) {
-    log('Long press: $location');
     widget.trip.landmarks.clear();
     widget.trip.addLandmark(
       Landmark(
-- 
2.47.2


From 8f6dfd404d6acc6e5bb854f9337c0b5494e906b8 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Fri, 14 Feb 2025 12:23:41 +0100
Subject: [PATCH 2/7] more pleasant progress handling, although somewhat flawed

---
 .../modules/current_trip_landmarks_list.dart  |  21 +-
 frontend/lib/modules/current_trip_map.dart    |  69 ++++-
 frontend/lib/modules/current_trip_panel.dart  |  38 ++-
 .../lib/modules/current_trip_summary.dart     |  34 ++-
 frontend/lib/modules/landmark_card.dart       | 281 ++++++++++--------
 frontend/lib/modules/landmark_map_marker.dart |   2 +-
 frontend/lib/structs/landmark.dart            |   6 +-
 frontend/lib/structs/trip.dart                |   8 +-
 8 files changed, 287 insertions(+), 172 deletions(-)

diff --git a/frontend/lib/modules/current_trip_landmarks_list.dart b/frontend/lib/modules/current_trip_landmarks_list.dart
index 39333f6..c92e920 100644
--- a/frontend/lib/modules/current_trip_landmarks_list.dart
+++ b/frontend/lib/modules/current_trip_landmarks_list.dart
@@ -7,14 +7,11 @@ import 'package:anyway/structs/landmark.dart';
 import 'package:anyway/structs/trip.dart';
 
 
-
-List<Widget> landmarksList(Trip trip) {
-  log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
+// Returns a list of widgets that represent the landmarks matching the given selector
+List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector}) {
   
   List<Widget> children = [];
 
-  log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
-
   if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == typeStart ) {
     children.add(
       const Text("No landmarks in this trip"),
@@ -23,14 +20,16 @@ List<Widget> landmarksList(Trip trip) {
   }
 
   for (Landmark landmark in trip.landmarks) {
-    children.add(
-      LandmarkCard(landmark, trip),
-    );
-
-    if (landmark.next != null) {
+    if (selector(landmark)) {
       children.add(
-        StepBetweenLandmarks(current: landmark, next: landmark.next!)
+        LandmarkCard(landmark, trip),
       );
+
+      if (!landmark.visited && landmark.next != null) {
+        children.add(
+          StepBetweenLandmarks(current: landmark, next: landmark.next!)
+        );
+      }
     }
   }
 
diff --git a/frontend/lib/modules/current_trip_map.dart b/frontend/lib/modules/current_trip_map.dart
index 9efdc4c..1802404 100644
--- a/frontend/lib/modules/current_trip_map.dart
+++ b/frontend/lib/modules/current_trip_map.dart
@@ -9,14 +9,10 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'package:widget_to_marker/widget_to_marker.dart';
 
-
 class CurrentTripMap extends StatefulWidget {
-
   final Trip? trip;
 
-  CurrentTripMap({
-    this.trip
-  });
+  CurrentTripMap({this.trip});
 
   @override
   State<CurrentTripMap> createState() => _CurrentTripMapState();
@@ -30,7 +26,23 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
     zoom: 11.0,
   );
   Set<Marker> mapMarkers = <Marker>{};
-  
+  Set<Polyline> mapPolylines = <Polyline>{};
+
+  @override
+  void initState() {
+    super.initState();
+    widget.trip?.addListener(setMapMarkers);
+    widget.trip?.addListener(setMapRoute);
+
+  }
+
+  @override
+  void dispose() {
+    widget.trip?.removeListener(setMapMarkers);
+    widget.trip?.removeListener(setMapRoute);
+    
+    super.dispose();
+  }
 
   void _onMapCreated(GoogleMapController controller) async {
     mapController = controller;
@@ -40,16 +52,17 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
       controller.moveCamera(update);
     }
     setMapMarkers();
+    setMapRoute();
   }
 
   void _onCameraIdle() {
     // print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
   }
 
-
   void setMapMarkers() async {
     List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
-    Set<Marker> newMarkers = <Marker>{};
+    Set<Marker> markers = <Marker>{};
+
     for (int i = 0; i < landmarks.length; i++) {
       Landmark landmark = landmarks[i];
       List<double> location = landmark.location;
@@ -58,20 +71,47 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
         position: LatLng(location[0], location[1]),
         icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
           logicalSize: const Size(150, 150),
-          imageSize: const Size(150, 150)
+          imageSize: const Size(150, 150),
         ),
       );
-      newMarkers.add(marker);
+      markers.add(marker);
     }
     setState(() {
-      mapMarkers = newMarkers;
+      mapMarkers = markers;
     });
   }
 
+  void setMapRoute() async {
+    List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
+    Set<Polyline> polyLines = <Polyline>{};
+
+    if (landmarks.length < 2) {
+      return;
+    }
+
+    for (Landmark landmark in landmarks) {
+      if (landmark.next != null) {
+        List<LatLng> step = [
+          LatLng(landmark.location[0], landmark.location[1]),
+          LatLng(landmark.next!.location[0], landmark.next!.location[1])
+        ];
+        Polyline stepLine = Polyline(
+          polylineId: PolylineId('step-${landmark.uuid}'),
+          points: step,
+          color: landmark.visited ? Colors.grey : PRIMARY_COLOR,
+          width: 5,
+        );
+        polyLines.add(stepLine);
+      }
+    }
+
+    setState(() {
+      mapPolylines = polyLines;
+    });
+  }
 
   @override
   Widget build(BuildContext context) {
-    widget.trip?.addListener(setMapMarkers);
     Future<SharedPreferences> preferences = SharedPreferences.getInstance();
 
     return FutureBuilder(
@@ -84,7 +124,7 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
         } else {
           return const CircularProgressIndicator();
         }
-      }
+      },
     );
   }
 
@@ -93,8 +133,8 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
       onMapCreated: _onMapCreated,
       initialCameraPosition: _cameraPosition,
       onCameraIdle: _onCameraIdle,
-      // onLongPress: ,
       markers: mapMarkers,
+      polylines: mapPolylines,
       cloudMapId: MAP_ID,
       mapToolbarEnabled: false,
       zoomControlsEnabled: false,
@@ -102,5 +142,4 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
       myLocationButtonEnabled: false,
     );
   }
-
 }
diff --git a/frontend/lib/modules/current_trip_panel.dart b/frontend/lib/modules/current_trip_panel.dart
index 0cf111b..230c4c3 100644
--- a/frontend/lib/modules/current_trip_panel.dart
+++ b/frontend/lib/modules/current_trip_panel.dart
@@ -1,6 +1,7 @@
 import 'package:anyway/constants.dart';
 import 'package:anyway/modules/current_trip_error_message.dart';
 import 'package:anyway/modules/current_trip_loading_indicator.dart';
+import 'package:anyway/structs/landmark.dart';
 import 'package:flutter/material.dart';
 
 import 'package:anyway/structs/trip.dart';
@@ -63,13 +64,40 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
                 child: CurrentTripGreeter(trip: widget.trip),
               ),
 
+              Padding(
+                padding: EdgeInsets.all(10),
+                child: Container(
+                  decoration: BoxDecoration(
+                    color: Colors.grey[100],
+                    borderRadius: BorderRadius.circular(10),
+                  ),
+                  child: Column(
+                    children: [
+                      CurrentTripSummary(trip: widget.trip),
+                      ExpansionTile(
+                        leading: Icon(Icons.location_on),
+                        title: Text('Visited Landmarks (tap to expand)'),
+                        children: [
+                          ...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
+                        ],
+                        visualDensity: VisualDensity.compact,
+                        collapsedShape: RoundedRectangleBorder(
+                          borderRadius: BorderRadius.circular(10),
+                        ),
+                        shape: RoundedRectangleBorder(
+                          borderRadius: BorderRadius.circular(10),
+                        ),
+                      ),
+                    ],
+                  ),
+                ),
+              ),
+              
+
               const Padding(padding: EdgeInsets.only(top: 10)),
 
-              // CurrentTripSummary(trip: widget.trip),
-
-              // const Divider(),
-
-              ...landmarksList(widget.trip),
+              // upcoming landmarks
+              ...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited == false),
 
               const Padding(padding: EdgeInsets.only(top: 10)),
 
diff --git a/frontend/lib/modules/current_trip_summary.dart b/frontend/lib/modules/current_trip_summary.dart
index 77c9461..bc46092 100644
--- a/frontend/lib/modules/current_trip_summary.dart
+++ b/frontend/lib/modules/current_trip_summary.dart
@@ -15,17 +15,27 @@ class CurrentTripSummary extends StatefulWidget {
 class _CurrentTripSummaryState extends State<CurrentTripSummary> {
   @override
   Widget build(BuildContext context) {
-    return Column(
-      children: [
-        Text('Summary'),
-        // Text('Start: ${widget.trip.start}'),
-        // Text('End: ${widget.trip.end}'),
-        Text('Total duration: ${widget.trip.totalTime}'),
-        Text('Total distance: ${widget.trip.totalTime}'),
-        // Text('Fuel: ${widget.trip.fuel}'),
-        // Text('Cost: ${widget.trip.cost}'),
-      ],
+    return Padding(
+      padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: [
+          Row(
+            children: [
+              Icon(Icons.flag, size: 20),
+              Padding(padding: EdgeInsets.only(right: 10)),
+              Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge,),
+            ]
+          ),
+          Row(
+            children: [
+              Icon(Icons.hourglass_bottom_rounded, size: 20),
+              Padding(padding: EdgeInsets.only(right: 10)),
+              Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge,),
+            ]
+          ),
+        ],
+      )
     );
-    
   }
-}
\ No newline at end of file
+}
diff --git a/frontend/lib/modules/landmark_card.dart b/frontend/lib/modules/landmark_card.dart
index e920e79..e3e8a75 100644
--- a/frontend/lib/modules/landmark_card.dart
+++ b/frontend/lib/modules/landmark_card.dart
@@ -1,3 +1,4 @@
+import 'package:anyway/constants.dart';
 import 'package:anyway/main.dart';
 import 'package:anyway/structs/trip.dart';
 import 'package:flutter/material.dart';
@@ -13,7 +14,7 @@ class LandmarkCard extends StatefulWidget {
   LandmarkCard(
     this.landmark,
     this.parentTrip,
-    );
+  );
   
   @override
   _LandmarkCardState createState() => _LandmarkCardState();
@@ -31,142 +32,176 @@ class _LandmarkCardState extends State<LandmarkCard> {
       );
 
     }
-    // else:
+
     return Container(
+      constraints: BoxConstraints(
+        minHeight: 50,
+        maxHeight: 200,
+      ),
       child: Card(
         shape: RoundedRectangleBorder(
           borderRadius: BorderRadius.circular(15.0),
         ),
         elevation: 5,
         clipBehavior: Clip.antiAliasWithSaveLayer,
+        
         // if the image is available, display it on the left side of the card, otherwise only display the text
-        child: widget.landmark.imageURL != null ? splitLayout() : textLayout(),
-      ),
-    );
-  }
-
-  Widget splitLayout() {
-    // If an image is available, display it on the left side of the card
-    return Row(
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: [
-        Container(
-          // the image on the left
-          width: 160,
-          height: 160,
-
-          child: CachedNetworkImage(
-            imageUrl: widget.landmark.imageURL ?? '',
-            placeholder: (context, url) => Center(child: CircularProgressIndicator()),
-            errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined),
-            fit: BoxFit.cover,
-          ),
-        ),
-        Flexible(
-          child: textLayout(),
-        ),
-      ],
-    );
-  }
-
-  Widget textLayout() {
-    return Padding(
-      padding: EdgeInsets.all(10),
-      child: Column(
-        children: [
-          Row(
-            children: [
-              Flexible(
-                child: Text(
-                  widget.landmark.name,
-                  style: const TextStyle(
-                    fontSize: 18,
-                    fontWeight: FontWeight.bold,
-                  ),
-                  maxLines: 2,
-                ),
-              )
-            ],
-          ),
-          if (widget.landmark.nameEN != null)
-            Row(
-              children: [
-                Flexible(
-                  child: Text(
-                    widget.landmark.nameEN!,
-                    style: const TextStyle(
-                      fontSize: 16,
-                    ),
-                    maxLines: 1,
-                  ),
-                )
-              ],
-            ),
-          Padding(padding: EdgeInsets.only(top: 10)),
-          Align(
-            alignment: Alignment.centerLeft,
-            child: SingleChildScrollView(
-              // allows the buttons to be scrolled
-              scrollDirection: Axis.horizontal,
-              child: Wrap(
-                spacing: 10,
-                // show the type, the website, and the wikipedia link as buttons/labels in a row
+        child: Row(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            // Image and landmark "type" on the left
+            AspectRatio(
+              aspectRatio: 3 / 4,
+              child: Column(
                 children: [
-                  TextButton.icon(
-                    onPressed: () {},
-                    icon: widget.landmark.type.icon,
-                    label: Text(widget.landmark.type.name),
-                  ),
-                  if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
-                    TextButton.icon(
-                      onPressed: () {},
-                      icon: Icon(Icons.hourglass_bottom),
-                      label: Text('${widget.landmark.duration!.inMinutes} minutes'),
-                    ),
-                  if (widget.landmark.websiteURL != null)
-                    TextButton.icon(
-                      onPressed: () async {
-                        // open a browser with the website link
-                        await launchUrl(Uri.parse(widget.landmark.websiteURL!));
-                      },
-                      icon: Icon(Icons.link),
-                      label: Text('Website'),
-                    ),
-                  PopupMenuButton(
-                    icon: Icon(Icons.settings),
-                    style: TextButtonTheme.of(context).style,
-                    itemBuilder: (context) => [
-                      PopupMenuItem(
-                        child: ListTile(
-                          leading: Icon(Icons.delete),
-                          title: Text('Delete'),
-                          onTap: () async {
-                            widget.parentTrip.removeLandmark(widget.landmark);
-                            rootScaffoldMessengerKey.currentState!.showSnackBar(
-                              SnackBar(content: Text("We won't show ${widget.landmark.name} again"))
-                            );
-                          },
+                  if (widget.landmark.imageURL != null && widget.landmark.imageURL!.isNotEmpty)
+                    Expanded(
+                      child: CachedNetworkImage(
+                        imageUrl: widget.landmark.imageURL!,
+                        placeholder: (context, url) => Center(child: CircularProgressIndicator()),
+                        errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined),
+                        fit: BoxFit.cover,
+                      )
+                    )
+                  else
+                    Expanded(
+                      child: 
+                      Container(
+                        decoration: BoxDecoration(
+                          gradient: LinearGradient(
+                            begin: Alignment.topLeft,
+                            end: Alignment.bottomRight,
+                            colors: [GRADIENT_START, GRADIENT_END],
+                          ),
+                        ),
+                        child: Center(
+                          child: Icon(widget.landmark.type.icon.icon, size: 50),
                         ),
                       ),
-                      PopupMenuItem(
-                        child: ListTile(
-                          leading: Icon(Icons.star),
-                          title: Text('Favorite'),
-                          onTap: () async {
-                            // delete the landmark
-                            // await deleteLandmark(widget.landmark);
-                          },
-                        ),
-                      ),
-                    ],
+                    ),
+
+                  Container(
+                    color: PRIMARY_COLOR,
+                    child: Center(
+                      child: Padding(
+                        padding: EdgeInsets.all(5),
+                        child: Row(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          spacing: 5,
+                          children: [
+                            Icon(widget.landmark.type.icon.icon, size: 16),
+                            Text(widget.landmark.type.name, style: TextStyle(fontWeight: FontWeight.bold)),
+                          ],
+                        )
+                      )
+                    ),
                   )
-                    
                 ],
-              ),
+              )
             ),
-          ),
-        ],
-      ),
+
+            // Main information, useful buttons on the right
+            Expanded(
+              child: Padding(
+                padding: const EdgeInsets.all(10),
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    Text(
+                      widget.landmark.name,
+                      style: Theme.of(context).textTheme.titleMedium,
+                      overflow: TextOverflow.ellipsis,
+                      maxLines: 2,
+                    ),
+                      
+                    if (widget.landmark.nameEN != null)
+                      Text(
+                        widget.landmark.nameEN!,
+                        style: Theme.of(context).textTheme.bodyMedium,
+                        maxLines: 1,
+                        overflow: TextOverflow.ellipsis,
+                      ),
+
+                    // fill the vspace
+                    const Spacer(),
+
+                    SingleChildScrollView(
+                      // allows the buttons to be scrolled
+                      scrollDirection: Axis.horizontal,
+                      child: Wrap(
+                        spacing: 10,
+                        // show the type, the website, and the wikipedia link as buttons/labels in a row
+                        children: [
+                          doneToggleButton(),
+                          // if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
+                          //   TextButton.icon(
+                          //     onPressed: () {},
+                          //     icon: Icon(Icons.hourglass_bottom),
+                          //     label: Text('${widget.landmark.duration!.inMinutes} minutes'),
+                          //   ),
+                          if (widget.landmark.websiteURL != null)
+                            websiteButton(),
+                          
+                          optionsButton()
+                        ],
+                      ),
+                    ),
+                  ],
+                ),
+              ),
+            )
+          ],
+        )
+      )
     );
   }
+
+  Widget doneToggleButton() {
+    return TextButton.icon(
+      onPressed: () async {
+        widget.landmark.visited = !widget.landmark.visited;
+        widget.parentTrip.notifyUpdate();
+      },
+      icon: Icon(widget.landmark.visited ? Icons.undo_sharp : Icons.check),
+      label: Text(widget.landmark.visited ? "Add to overview" : "Done!"),
+    );
+  }
+
+  Widget websiteButton () => TextButton.icon(
+    onPressed: () async {
+      // open a browser with the website link
+      await launchUrl(Uri.parse(widget.landmark.websiteURL!));
+    },
+    icon: Icon(Icons.link),
+    label: Text('Website'),
+  );
+
+  Widget optionsButton () => PopupMenuButton(
+    icon: Icon(Icons.settings),
+    style: TextButtonTheme.of(context).style,
+    itemBuilder: (context) => [
+      PopupMenuItem(
+        child: ListTile(
+          leading: Icon(Icons.delete),
+          title: Text('Delete'),
+          onTap: () async {
+            widget.parentTrip.removeLandmark(widget.landmark);
+            rootScaffoldMessengerKey.currentState!.showSnackBar(
+              SnackBar(content: Text("We won't show ${widget.landmark.name} again"))
+            );
+          },
+        ),
+      ),
+      PopupMenuItem(
+        child: ListTile(
+          leading: Icon(Icons.star),
+          title: Text('Favorite'),
+          onTap: () async {
+            // delete the landmark
+            // await deleteLandmark(widget.landmark);
+          },
+        ),
+      ),
+    ],
+  );
 }
diff --git a/frontend/lib/modules/landmark_map_marker.dart b/frontend/lib/modules/landmark_map_marker.dart
index 2e8f5d7..fccf50a 100644
--- a/frontend/lib/modules/landmark_map_marker.dart
+++ b/frontend/lib/modules/landmark_map_marker.dart
@@ -40,7 +40,7 @@ class ThemedMarker extends StatelessWidget {
         children: [
           Container(
             decoration: BoxDecoration(
-              gradient: APP_GRADIENT,
+              gradient: landmark.visited ? LinearGradient(colors: [Colors.grey, Colors.white]) : APP_GRADIENT,
               shape: BoxShape.circle,
               border: Border.all(color: Colors.black, width: 5),
             ),
diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart
index 50a71c5..a0e5905 100644
--- a/frontend/lib/structs/landmark.dart
+++ b/frontend/lib/structs/landmark.dart
@@ -27,7 +27,7 @@ final class Landmark extends LinkedListEntry<Landmark>{
   String? imageURL; // not final because it can be patched
   final String? description;
   final Duration? duration;
-  final bool? visited;
+  bool visited;
 
   // Next node
   // final Landmark? next;
@@ -46,7 +46,7 @@ final class Landmark extends LinkedListEntry<Landmark>{
     this.imageURL,
     this.description,
     this.duration,
-    this.visited,
+    this.visited = false,
 
     // this.next,
     this.tripTime,
@@ -71,7 +71,7 @@ final class Landmark extends LinkedListEntry<Landmark>{
       final imageURL = json['image_url'] as String?;
       final description = json['description'] as String?;
       var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
-      final visited = json['visited'] as bool?;
+      final visited = json['visited'] ?? false as bool;
       var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
       
       return Landmark(
diff --git a/frontend/lib/structs/trip.dart b/frontend/lib/structs/trip.dart
index 44e12c3..8d816ca 100644
--- a/frontend/lib/structs/trip.dart
+++ b/frontend/lib/structs/trip.dart
@@ -52,6 +52,7 @@ class Trip with ChangeNotifier {
     totalTime = json['total_time'];
     notifyListeners();
   }
+
   void addLandmark(Landmark landmark) {
     landmarks.add(landmark);
     notifyListeners();
@@ -66,12 +67,16 @@ class Trip with ChangeNotifier {
     landmarks.remove(landmark);
     notifyListeners();
   }
-  
+
   void updateError(String error) {
     errorDescription = error;
     notifyListeners();
   }
 
+  void notifyUpdate(){
+    notifyListeners();
+  }
+
   factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
     String? content = prefs.getString('trip_$uuid');
     Map<String, dynamic> json = jsonDecode(content!);
@@ -80,7 +85,6 @@ class Trip with ChangeNotifier {
     log('Loading trip $uuid with first landmark $firstUUID');
     LinkedList<Landmark> landmarks = readLandmarks(prefs, firstUUID);
     trip.landmarks = landmarks;
-    // notifyListeners();
     return trip;
   }
 
-- 
2.47.2


From 56c55883ea778a26da253595458cddffb1b3fe9a Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sat, 15 Feb 2025 19:36:41 +0100
Subject: [PATCH 3/7] reworked page layout inheritence

---
 .../base_page.dart => layouts/scaffold.dart}  | 74 ++++++----------
 frontend/lib/main.dart                        | 23 ++---
 .../modules/current_trip_landmarks_list.dart  |  6 +-
 .../current_trip_loading_indicator.dart       | 15 ++--
 frontend/lib/modules/current_trip_map.dart    | 51 ++++++-----
 frontend/lib/modules/current_trip_panel.dart  | 39 +++++----
 .../lib/modules/current_trip_save_button.dart |  5 +-
 .../lib/modules/current_trip_summary.dart     | 15 ++--
 frontend/lib/modules/help_dialog.dart         |  2 +-
 frontend/lib/modules/landmark_card.dart       | 86 ++++++++-----------
 frontend/lib/modules/new_trip_button.dart     |  5 +-
 frontend/lib/modules/new_trip_map.dart        | 14 +--
 .../lib/modules/step_between_landmarks.dart   | 37 ++++----
 frontend/lib/pages/current_trip.dart          | 15 ++--
 frontend/lib/pages/new_trip_location.dart     |  9 +-
 frontend/lib/pages/new_trip_preferences.dart  | 32 +++----
 frontend/lib/pages/settings.dart              | 63 +++++++-------
 frontend/lib/structs/landmark.dart            |  6 +-
 frontend/lib/structs/trip.dart                | 12 +++
 frontend/lib/utils/fetch_trip.dart            | 32 +++----
 frontend/lib/utils/get_first_page.dart        | 15 ++--
 21 files changed, 278 insertions(+), 278 deletions(-)
 rename frontend/lib/{pages/base_page.dart => layouts/scaffold.dart} (67%)

diff --git a/frontend/lib/pages/base_page.dart b/frontend/lib/layouts/scaffold.dart
similarity index 67%
rename from frontend/lib/pages/base_page.dart
rename to frontend/lib/layouts/scaffold.dart
index ce36f1f..e927e5f 100644
--- a/frontend/lib/pages/base_page.dart
+++ b/frontend/lib/layouts/scaffold.dart
@@ -1,72 +1,51 @@
-import 'package:anyway/main.dart';
-import 'package:anyway/modules/help_dialog.dart';
-import 'package:anyway/pages/current_trip.dart';
-import 'package:anyway/pages/settings.dart';
 import 'package:flutter/material.dart';
 
 import 'package:anyway/constants.dart';
 
-import 'package:anyway/structs/trip.dart';
+import 'package:anyway/main.dart';
+import 'package:anyway/modules/help_dialog.dart';
 import 'package:anyway/modules/trips_saved_list.dart';
-import 'package:anyway/utils/load_trips.dart';
 
-import 'package:anyway/pages/new_trip_location.dart';
 import 'package:anyway/pages/onboarding.dart';
+import 'package:anyway/pages/current_trip.dart';
+import 'package:anyway/pages/settings.dart';
+import 'package:anyway/pages/new_trip_location.dart';
 
 
-
-
-// BasePage is the scaffold that holds a child page and a side drawer
-// The side drawer is the main way to switch between pages
-
-class BasePage extends StatefulWidget {
-  final Widget mainScreen;
-  final Widget title;
-  final List<String> helpTexts;
-
-  const BasePage({
-    super.key,
-    required this.mainScreen,
-    this.title = const Text(APP_NAME),
-    this.helpTexts = const [],
-  });
-
-  @override
-  State<BasePage> createState() => _BasePageState();
-}
-
-class _BasePageState extends State<BasePage> {
-
-  @override
-  Widget build(BuildContext context) {
-    savedTrips.loadTrips();
-
-
+mixin ScaffoldLayout<T extends StatefulWidget> on State<T> {
+  Widget mainScaffold(
+    BuildContext context,
+    {
+      Widget child = const Text("emptiness"),
+      Widget title = const Text(APP_NAME),
+      List<String> helpTexts = const []
+    }
+  ) {
     return Scaffold(
       appBar: AppBar(
-        title: widget.title,
+        title: title,
         actions: [
           IconButton(
             icon: const Icon(Icons.help),
             tooltip: 'Help',
             onPressed: () {
-              if (widget.helpTexts.isNotEmpty) {
-                helpDialog(context, widget.helpTexts[0], widget.helpTexts[1]);
+              if (helpTexts.isNotEmpty) {
+                helpDialog(context, helpTexts[0], helpTexts[1]);
               }
             }
           ),
         ],
       ),
-      body: Center(child: widget.mainScreen),
+      body: Center(child: child),
       drawer: Drawer(
         child: Column(
           children: [
             Container(
-              decoration: BoxDecoration(
+              decoration: const BoxDecoration(
                 gradient: APP_GRADIENT,
               ),
               height: 150,
-              child: Center(
+              child: const Center(
                 child: Text(
                   APP_NAME,
                   style: TextStyle(
@@ -81,8 +60,7 @@ class _BasePageState extends State<BasePage> {
             ListTile(
               title: const Text('Your Trips'),
               leading: const Icon(Icons.map),
-              // TODO: this is not working!
-              selected: widget.mainScreen is TripPage,
+              selected: widget is TripPage,
               onTap: () {},
               trailing: ElevatedButton(
                 onPressed: () {
@@ -111,13 +89,12 @@ class _BasePageState extends State<BasePage> {
             const Divider(indent: 10, endIndent: 10),
             ListTile(
               title: const Text('How to use'),
-              leading: Icon(Icons.help),
-              // TODO: this is not working!
-              selected: widget.mainScreen is OnboardingPage,
+              leading: const Icon(Icons.help),
+              selected: widget is OnboardingPage,
               onTap: () {
                 Navigator.of(context).push(
                   MaterialPageRoute(
-                    builder: (context) => OnboardingPage()
+                    builder: (context) => const OnboardingPage()
                   )
                 );
               },
@@ -127,8 +104,7 @@ class _BasePageState extends State<BasePage> {
             ListTile(
               title: const Text('Settings'),
               leading: const Icon(Icons.settings),
-              // TODO: this is not working!
-              selected: widget.mainScreen is SettingsPage,
+              selected: widget is SettingsPage,
               onTap: () {
                 Navigator.of(context).push(
                   MaterialPageRoute(
diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart
index 5f3dc49..ed4121f 100644
--- a/frontend/lib/main.dart
+++ b/frontend/lib/main.dart
@@ -1,24 +1,27 @@
+import 'package:flutter/material.dart';
+
+import 'package:anyway/constants.dart';
 import 'package:anyway/utils/get_first_page.dart';
 import 'package:anyway/utils/load_trips.dart';
-import 'package:flutter/material.dart';
-import 'package:anyway/constants.dart';
+
 
 void main() => runApp(const App());
 
+// Some global variables
 final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
 final SavedTrips savedTrips = SavedTrips();
+// the list of saved trips is then populated implicitly by getFirstPage()
+
 
 class App extends StatelessWidget {
   const App({super.key});
 
 
   @override
-  Widget build(BuildContext context) {
-    return MaterialApp(
-      title: APP_NAME,
-      home: getFirstPage(),
-      theme: APP_THEME,
-      scaffoldMessengerKey: rootScaffoldMessengerKey
-    );
-  }
+  Widget build(BuildContext context) => MaterialApp(
+    title: APP_NAME,
+    home: getFirstPage(),
+    theme: APP_THEME,
+    scaffoldMessengerKey: rootScaffoldMessengerKey
+  );
 }
diff --git a/frontend/lib/modules/current_trip_landmarks_list.dart b/frontend/lib/modules/current_trip_landmarks_list.dart
index c92e920..9ab4fbc 100644
--- a/frontend/lib/modules/current_trip_landmarks_list.dart
+++ b/frontend/lib/modules/current_trip_landmarks_list.dart
@@ -1,10 +1,9 @@
-import 'dart:developer';
-import 'package:anyway/modules/step_between_landmarks.dart';
 import 'package:flutter/material.dart';
 
-import 'package:anyway/modules/landmark_card.dart';
 import 'package:anyway/structs/landmark.dart';
 import 'package:anyway/structs/trip.dart';
+import 'package:anyway/modules/step_between_landmarks.dart';
+import 'package:anyway/modules/landmark_card.dart';
 
 
 // Returns a list of widgets that represent the landmarks matching the given selector
@@ -35,4 +34,3 @@ List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector
 
   return children;
 }
-
diff --git a/frontend/lib/modules/current_trip_loading_indicator.dart b/frontend/lib/modules/current_trip_loading_indicator.dart
index 96648a3..5eaf037 100644
--- a/frontend/lib/modules/current_trip_loading_indicator.dart
+++ b/frontend/lib/modules/current_trip_loading_indicator.dart
@@ -35,29 +35,29 @@ class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicato
       // In the very center of the panel, show the greeter which tells the user that the trip is being generated
       Center(child: loadingText(widget.trip)),
       // As a gimmick, and a way to show that the app is still working, show a few loading dots
-      Align(
+      const Align(
         alignment: Alignment.bottomCenter,
-        child: statusText(),
+        child: StatusText(),
       )
     ],
   );
 }
 
 // automatically cycle through the greeter texts
-class statusText extends StatefulWidget {
-  const statusText({Key? key}) : super(key: key);
+class StatusText extends StatefulWidget {
+  const StatusText({Key? key}) : super(key: key);
 
   @override
-  _statusTextState createState() => _statusTextState();
+  _StatusTextState createState() => _StatusTextState();
 }
 
-class _statusTextState extends State<statusText> {
+class _StatusTextState extends State<StatusText> {
   int statusIndex = 0;
 
   @override
   void initState() {
     super.initState();
-    Future.delayed(Duration(seconds: 5), () {
+    Future.delayed(const Duration(seconds: 5), () {
       setState(() {
         statusIndex = (statusIndex + 1) % statusTexts.length;
       });
@@ -159,4 +159,3 @@ class _AnimatedGradientTextState extends State<AnimatedGradientText> with Single
     );
   }
 }
-
diff --git a/frontend/lib/modules/current_trip_map.dart b/frontend/lib/modules/current_trip_map.dart
index 1802404..d1c6407 100644
--- a/frontend/lib/modules/current_trip_map.dart
+++ b/frontend/lib/modules/current_trip_map.dart
@@ -1,13 +1,14 @@
 import 'dart:collection';
+import 'package:flutter/material.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'package:google_maps_flutter/google_maps_flutter.dart';
+import 'package:widget_to_marker/widget_to_marker.dart';
 
 import 'package:anyway/constants.dart';
-import 'package:anyway/modules/landmark_map_marker.dart';
-import 'package:flutter/material.dart';
 import 'package:anyway/structs/landmark.dart';
 import 'package:anyway/structs/trip.dart';
-import 'package:google_maps_flutter/google_maps_flutter.dart';
-import 'package:shared_preferences/shared_preferences.dart';
-import 'package:widget_to_marker/widget_to_marker.dart';
+import 'package:anyway/modules/landmark_map_marker.dart';
+
 
 class CurrentTripMap extends StatefulWidget {
   final Trip? trip;
@@ -60,25 +61,29 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
   }
 
   void setMapMarkers() async {
-    List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
-    Set<Marker> markers = <Marker>{};
+    Iterator<(int, Landmark)> it = (widget.trip?.landmarks.toList() ?? []).indexed.iterator;
 
-    for (int i = 0; i < landmarks.length; i++) {
-      Landmark landmark = landmarks[i];
+    while (it.moveNext()) {
+      int i = it.current.$1;
+      Landmark landmark = it.current.$2;
+
+      MarkerId markerId = MarkerId("${landmark.uuid} - ${landmark.visited}");
       List<double> location = landmark.location;
-      Marker marker = Marker(
-        markerId: MarkerId(landmark.uuid),
-        position: LatLng(location[0], location[1]),
-        icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
-          logicalSize: const Size(150, 150),
-          imageSize: const Size(150, 150),
-        ),
-      );
-      markers.add(marker);
+      // only create a new marker, if there is no marker for this landmark
+      if (!mapMarkers.any((Marker marker) => marker.markerId == markerId)) {
+        Marker marker = Marker(
+          markerId: markerId,
+          position: LatLng(location[0], location[1]),
+          icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
+            logicalSize: const Size(150, 150),
+            imageSize: const Size(150, 150),
+          )
+        );
+        setState(() {
+          mapMarkers.add(marker);
+        });
+      }
     }
-    setState(() {
-      mapMarkers = markers;
-    });
   }
 
   void setMapRoute() async {
@@ -98,8 +103,8 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
         Polyline stepLine = Polyline(
           polylineId: PolylineId('step-${landmark.uuid}'),
           points: step,
-          color: landmark.visited ? Colors.grey : PRIMARY_COLOR,
-          width: 5,
+          color: landmark.visited || (landmark.next?.visited ?? false) ? Colors.grey : PRIMARY_COLOR,
+          width: 5
         );
         polyLines.add(stepLine);
       }
diff --git a/frontend/lib/modules/current_trip_panel.dart b/frontend/lib/modules/current_trip_panel.dart
index 230c4c3..8e55b83 100644
--- a/frontend/lib/modules/current_trip_panel.dart
+++ b/frontend/lib/modules/current_trip_panel.dart
@@ -1,10 +1,12 @@
-import 'package:anyway/constants.dart';
-import 'package:anyway/modules/current_trip_error_message.dart';
-import 'package:anyway/modules/current_trip_loading_indicator.dart';
-import 'package:anyway/structs/landmark.dart';
 import 'package:flutter/material.dart';
 
+import 'package:anyway/constants.dart';
+
+import 'package:anyway/structs/landmark.dart';
 import 'package:anyway/structs/trip.dart';
+
+import 'package:anyway/modules/current_trip_error_message.dart';
+import 'package:anyway/modules/current_trip_loading_indicator.dart';
 import 'package:anyway/modules/current_trip_summary.dart';
 import 'package:anyway/modules/current_trip_save_button.dart';
 import 'package:anyway/modules/current_trip_landmarks_list.dart';
@@ -74,20 +76,21 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
                   child: Column(
                     children: [
                       CurrentTripSummary(trip: widget.trip),
-                      ExpansionTile(
-                        leading: Icon(Icons.location_on),
-                        title: Text('Visited Landmarks (tap to expand)'),
-                        children: [
-                          ...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
-                        ],
-                        visualDensity: VisualDensity.compact,
-                        collapsedShape: RoundedRectangleBorder(
-                          borderRadius: BorderRadius.circular(10),
+                      if (widget.trip.landmarks.where((Landmark landmark) => landmark.visited).isNotEmpty)
+                        ExpansionTile(
+                          leading: const Icon(Icons.location_on),
+                          title: const Text('Visited Landmarks (tap to expand)'),
+                          children: [
+                            ...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
+                          ],
+                          visualDensity: VisualDensity.compact,
+                          collapsedShape: RoundedRectangleBorder(
+                            borderRadius: BorderRadius.circular(10),
+                          ),
+                          shape: RoundedRectangleBorder(
+                            borderRadius: BorderRadius.circular(10),
+                          ),
                         ),
-                        shape: RoundedRectangleBorder(
-                          borderRadius: BorderRadius.circular(10),
-                        ),
-                      ),
                     ],
                   ),
                 ),
@@ -108,4 +111,4 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
       }
     );
   }
-}  
+}
diff --git a/frontend/lib/modules/current_trip_save_button.dart b/frontend/lib/modules/current_trip_save_button.dart
index 0b8e773..64028e7 100644
--- a/frontend/lib/modules/current_trip_save_button.dart
+++ b/frontend/lib/modules/current_trip_save_button.dart
@@ -1,8 +1,8 @@
+import 'package:flutter/material.dart';
+import 'package:auto_size_text/auto_size_text.dart';
 
 import 'package:anyway/main.dart';
 import 'package:anyway/structs/trip.dart';
-import 'package:auto_size_text/auto_size_text.dart';
-import 'package:flutter/material.dart';
 
 
 class saveButton extends StatefulWidget {
@@ -52,4 +52,3 @@ class _saveButtonState extends State<saveButton> {
     );
   }
 }
-
diff --git a/frontend/lib/modules/current_trip_summary.dart b/frontend/lib/modules/current_trip_summary.dart
index bc46092..e7aa4a5 100644
--- a/frontend/lib/modules/current_trip_summary.dart
+++ b/frontend/lib/modules/current_trip_summary.dart
@@ -1,6 +1,7 @@
 import 'package:anyway/structs/trip.dart';
 import 'package:flutter/material.dart';
 
+
 class CurrentTripSummary extends StatefulWidget {
   final Trip trip;
   const CurrentTripSummary({
@@ -16,22 +17,22 @@ class _CurrentTripSummaryState extends State<CurrentTripSummary> {
   @override
   Widget build(BuildContext context) {
     return Padding(
-      padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
+      padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
       child: Row(
         mainAxisAlignment: MainAxisAlignment.spaceBetween,
         children: [
           Row(
             children: [
-              Icon(Icons.flag, size: 20),
-              Padding(padding: EdgeInsets.only(right: 10)),
-              Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge,),
+              const Icon(Icons.flag, size: 20),
+              const Padding(padding: EdgeInsets.only(right: 10)),
+              Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge),
             ]
           ),
           Row(
             children: [
-              Icon(Icons.hourglass_bottom_rounded, size: 20),
-              Padding(padding: EdgeInsets.only(right: 10)),
-              Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge,),
+              const Icon(Icons.hourglass_bottom_rounded, size: 20),
+              const Padding(padding: EdgeInsets.only(right: 10)),
+              Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge),
             ]
           ),
         ],
diff --git a/frontend/lib/modules/help_dialog.dart b/frontend/lib/modules/help_dialog.dart
index 75db7b0..caf94aa 100644
--- a/frontend/lib/modules/help_dialog.dart
+++ b/frontend/lib/modules/help_dialog.dart
@@ -1,6 +1,6 @@
-
 import 'package:flutter/material.dart';
 
+
 Future<void> helpDialog(BuildContext context, String title, String content) {
   return showDialog<void>(
     context: context,
diff --git a/frontend/lib/modules/landmark_card.dart b/frontend/lib/modules/landmark_card.dart
index e3e8a75..9ef4875 100644
--- a/frontend/lib/modules/landmark_card.dart
+++ b/frontend/lib/modules/landmark_card.dart
@@ -1,12 +1,15 @@
-import 'package:anyway/constants.dart';
-import 'package:anyway/main.dart';
-import 'package:anyway/structs/trip.dart';
 import 'package:flutter/material.dart';
 import 'package:cached_network_image/cached_network_image.dart';
-import 'package:url_launcher/url_launcher.dart';
 
+import 'package:anyway/constants.dart';
+
+import 'package:anyway/main.dart';
+import 'package:anyway/structs/trip.dart';
+import 'package:url_launcher/url_launcher.dart';
 import 'package:anyway/structs/landmark.dart';
 
+
+
 class LandmarkCard extends StatefulWidget {
   final Landmark landmark;
   final Trip parentTrip;
@@ -23,20 +26,11 @@ class LandmarkCard extends StatefulWidget {
 
 class _LandmarkCardState extends State<LandmarkCard> {
   @override
-  Widget build(BuildContext context) {
-    if (widget.landmark.type == typeStart || widget.landmark.type == typeFinish) {
-      return TextButton.icon(
-        onPressed: () {},
-        icon: widget.landmark.type.icon,
-        label: Text(widget.landmark.name),
-      );
-
-    }
-
+  Widget build(BuildContext context) {      
     return Container(
       constraints: BoxConstraints(
-        minHeight: 50,
-        maxHeight: 200,
+        // express the max height in terms text lines
+        maxHeight: 7 * (Theme.of(context).textTheme.titleMedium!.fontSize! + 10),
       ),
       child: Card(
         shape: RoundedRectangleBorder(
@@ -79,23 +73,23 @@ class _LandmarkCardState extends State<LandmarkCard> {
                         ),
                       ),
                     ),
-
-                  Container(
-                    color: PRIMARY_COLOR,
-                    child: Center(
-                      child: Padding(
-                        padding: EdgeInsets.all(5),
-                        child: Row(
-                          mainAxisAlignment: MainAxisAlignment.center,
-                          spacing: 5,
-                          children: [
-                            Icon(widget.landmark.type.icon.icon, size: 16),
-                            Text(widget.landmark.type.name, style: TextStyle(fontWeight: FontWeight.bold)),
-                          ],
+                  if (widget.landmark.type != typeStart && widget.landmark.type != typeFinish)
+                    Container(
+                      color: PRIMARY_COLOR,
+                      child: Center(
+                        child: Padding(
+                          padding: EdgeInsets.all(5),
+                          child: Row(
+                            mainAxisAlignment: MainAxisAlignment.center,
+                            spacing: 5,
+                            children: [
+                              Icon(Icons.timer_outlined, size: 16),
+                              Text("${widget.landmark.duration?.inMinutes} minutes"),
+                            ],
+                          )
                         )
-                      )
-                    ),
-                  )
+                      ),
+                    )
                 ],
               )
             ),
@@ -133,12 +127,6 @@ class _LandmarkCardState extends State<LandmarkCard> {
                         // show the type, the website, and the wikipedia link as buttons/labels in a row
                         children: [
                           doneToggleButton(),
-                          // if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
-                          //   TextButton.icon(
-                          //     onPressed: () {},
-                          //     icon: Icon(Icons.hourglass_bottom),
-                          //     label: Text('${widget.landmark.duration!.inMinutes} minutes'),
-                          //   ),
                           if (widget.landmark.websiteURL != null)
                             websiteButton(),
                           
@@ -172,33 +160,35 @@ class _LandmarkCardState extends State<LandmarkCard> {
       // open a browser with the website link
       await launchUrl(Uri.parse(widget.landmark.websiteURL!));
     },
-    icon: Icon(Icons.link),
-    label: Text('Website'),
+    icon: const Icon(Icons.link),
+    label: const Text('Website'),
   );
 
+
   Widget optionsButton () => PopupMenuButton(
-    icon: Icon(Icons.settings),
+    icon: const Icon(Icons.settings),
     style: TextButtonTheme.of(context).style,
     itemBuilder: (context) => [
       PopupMenuItem(
         child: ListTile(
-          leading: Icon(Icons.delete),
-          title: Text('Delete'),
+          leading: const Icon(Icons.delete),
+          title: const Text('Delete'),
           onTap: () async {
             widget.parentTrip.removeLandmark(widget.landmark);
             rootScaffoldMessengerKey.currentState!.showSnackBar(
-              SnackBar(content: Text("We won't show ${widget.landmark.name} again"))
+              SnackBar(content: Text("${widget.landmark.name} won't be shown again"))
             );
           },
         ),
       ),
       PopupMenuItem(
         child: ListTile(
-          leading: Icon(Icons.star),
-          title: Text('Favorite'),
+          leading: const Icon(Icons.star),
+          title: const Text('Favorite'),
           onTap: () async {
-            // delete the landmark
-            // await deleteLandmark(widget.landmark);
+            rootScaffoldMessengerKey.currentState!.showSnackBar(
+              SnackBar(content: Text("Not implemented yet"))
+            );
           },
         ),
       ),
diff --git a/frontend/lib/modules/new_trip_button.dart b/frontend/lib/modules/new_trip_button.dart
index 9dca910..3eb5d3b 100644
--- a/frontend/lib/modules/new_trip_button.dart
+++ b/frontend/lib/modules/new_trip_button.dart
@@ -46,11 +46,11 @@ class _NewTripButtonState extends State<NewTripButton> {
     UserPreferences preferences = widget.preferences;
     if (preferences.nature.value == 0 && preferences.shopping.value == 0 && preferences.sightseeing.value == 0){
       rootScaffoldMessengerKey.currentState!.showSnackBar(
-        SnackBar(content: Text("Please specify at least one preference"))
+        const SnackBar(content: Text("Please specify at least one preference"))
       );
     } else if (preferences.maxTime.value == 0){
       rootScaffoldMessengerKey.currentState!.showSnackBar(
-        SnackBar(content: Text("Please choose a longer duration"))
+        const SnackBar(content: Text("Please choose a longer duration"))
       );
     } else {
       Trip trip = widget.trip;
@@ -63,4 +63,3 @@ class _NewTripButtonState extends State<NewTripButton> {
     }
   }
 }
-
diff --git a/frontend/lib/modules/new_trip_map.dart b/frontend/lib/modules/new_trip_map.dart
index 02d4174..e4e5400 100644
--- a/frontend/lib/modules/new_trip_map.dart
+++ b/frontend/lib/modules/new_trip_map.dart
@@ -1,14 +1,14 @@
 // A map that allows the user to select a location for a new trip.
-import 'dart:developer';
+import 'package:flutter/material.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'package:google_maps_flutter/google_maps_flutter.dart';
+import 'package:widget_to_marker/widget_to_marker.dart';
 
 import 'package:anyway/constants.dart';
-import 'package:anyway/modules/landmark_map_marker.dart';
-import 'package:anyway/structs/landmark.dart';
+
 import 'package:anyway/structs/trip.dart';
-import 'package:flutter/material.dart';
-import 'package:google_maps_flutter/google_maps_flutter.dart';
-import 'package:shared_preferences/shared_preferences.dart';
-import 'package:widget_to_marker/widget_to_marker.dart';
+import 'package:anyway/structs/landmark.dart';
+import 'package:anyway/modules/landmark_map_marker.dart';
 
 
 class NewTripMap extends StatefulWidget {
diff --git a/frontend/lib/modules/step_between_landmarks.dart b/frontend/lib/modules/step_between_landmarks.dart
index b238cc1..739f1b6 100644
--- a/frontend/lib/modules/step_between_landmarks.dart
+++ b/frontend/lib/modules/step_between_landmarks.dart
@@ -1,7 +1,9 @@
-import 'package:anyway/structs/landmark.dart';
 import 'package:flutter/material.dart';
+
+import 'package:anyway/structs/landmark.dart';
 import 'package:anyway/modules/map_chooser.dart';
 
+
 class StepBetweenLandmarks extends StatefulWidget {
   final Landmark current;
   final Landmark next;
@@ -19,11 +21,15 @@ class StepBetweenLandmarks extends StatefulWidget {
 class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
   @override
   Widget build(BuildContext context) {
-    int time = widget.current.tripTime?.inMinutes ?? 0;
+    int? time = widget.current.tripTime?.inMinutes;
+    if (time != null && time < 1) {
+      time = 1;
+    }
+
     return Container(
-      margin: EdgeInsets.all(10),
-      padding: EdgeInsets.all(10),
-      decoration: BoxDecoration(
+      margin: const EdgeInsets.all(10),
+      padding: const EdgeInsets.all(10),
+      decoration: const BoxDecoration(
         border: Border(
           left: BorderSide(width: 3.0, color: Colors.black),
         ),
@@ -32,21 +38,22 @@ class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
         children: [
           Column(
             children: [
-              Icon(Icons.directions_walk),
-              Text("$time min", style: TextStyle(fontSize: 10)),
+              const Icon(Icons.directions_walk),
+              Text(
+                time == null ? "" : "About $time min",
+                style: const TextStyle(fontSize: 10)
+              ),
             ],
           ),
-          Spacer(),
-          ElevatedButton(
+
+          const Spacer(),
+
+          ElevatedButton.icon(
             onPressed: () async {
               showMapChooser(context, widget.current, widget.next);
             },
-            child: Row(
-              children: [
-                Icon(Icons.directions),
-                Text("Directions"),
-              ],
-            ),
+            icon: const Icon(Icons.directions),
+            label: const Text("Directions"),
           )
         ],
       ),
diff --git a/frontend/lib/pages/current_trip.dart b/frontend/lib/pages/current_trip.dart
index 6f45e7f..8f70652 100644
--- a/frontend/lib/pages/current_trip.dart
+++ b/frontend/lib/pages/current_trip.dart
@@ -1,5 +1,5 @@
 import 'package:anyway/constants.dart';
-import 'package:anyway/pages/base_page.dart';
+import 'package:anyway/layouts/scaffold.dart';
 import 'package:flutter/material.dart';
 import 'package:sliding_up_panel/sliding_up_panel.dart';
 
@@ -28,12 +28,13 @@ class TripPage extends StatefulWidget {
 
 
 
-class _TripPageState extends State<TripPage> {
+class _TripPageState extends State<TripPage> with ScaffoldLayout{
 
   @override
   Widget build(BuildContext context) {
-    return BasePage(
-      mainScreen: SlidingUpPanel(
+    return mainScaffold(
+      context,
+      child: SlidingUpPanel(
         // use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview
         panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip),
         // using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder
@@ -58,9 +59,13 @@ class _TripPageState extends State<TripPage> {
       title: FutureBuilder(
         future: widget.trip.cityName,
         builder: (context, snapshot) => Text(
-          'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
+          'Trip to ${snapshot.hasData ? snapshot.data! : "..."}',
         )
       ),
+      helpTexts: [
+        'Current trip',
+        'You can see and edit your current trip here. Swipe up from the bottom to see a detailed view of the recommendations.'
+      ],
     );
   }
 }
diff --git a/frontend/lib/pages/new_trip_location.dart b/frontend/lib/pages/new_trip_location.dart
index 2fba16f..cca895d 100644
--- a/frontend/lib/pages/new_trip_location.dart
+++ b/frontend/lib/pages/new_trip_location.dart
@@ -1,5 +1,5 @@
+import 'package:anyway/layouts/scaffold.dart';
 import 'package:anyway/modules/new_trip_options_button.dart';
-import 'package:anyway/pages/base_page.dart';
 import 'package:flutter/material.dart';
 
 import "package:anyway/structs/trip.dart";
@@ -14,7 +14,7 @@ class NewTripPage extends StatefulWidget {
   _NewTripPageState createState() => _NewTripPageState();
 }
 
-class _NewTripPageState extends State<NewTripPage> {
+class _NewTripPageState extends State<NewTripPage> with ScaffoldLayout {
   final TextEditingController latController = TextEditingController();
   final TextEditingController lonController = TextEditingController();
   Trip trip = Trip();
@@ -23,8 +23,9 @@ class _NewTripPageState extends State<NewTripPage> {
   @override
   Widget build(BuildContext context) {
     // floating search bar and map as a background
-    return BasePage(
-      mainScreen: Scaffold(
+    return mainScaffold(
+      context,
+      child: Scaffold(
         body: Stack(
           children: [
             NewTripMap(trip),
diff --git a/frontend/lib/pages/new_trip_preferences.dart b/frontend/lib/pages/new_trip_preferences.dart
index 15b7066..76aaf10 100644
--- a/frontend/lib/pages/new_trip_preferences.dart
+++ b/frontend/lib/pages/new_trip_preferences.dart
@@ -1,5 +1,5 @@
+import 'package:anyway/layouts/scaffold.dart';
 import 'package:anyway/modules/new_trip_button.dart';
-import 'package:anyway/pages/base_page.dart';
 import 'package:anyway/structs/preferences.dart';
 import 'package:anyway/structs/trip.dart';
 import 'package:flutter/cupertino.dart';
@@ -15,13 +15,14 @@ class NewTripPreferencesPage extends StatefulWidget {
   _NewTripPreferencesPageState createState() => _NewTripPreferencesPageState();
 }
 
-class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
+class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> with ScaffoldLayout {
   UserPreferences preferences = UserPreferences();
 
   @override
   Widget build(BuildContext context) {
-    return BasePage(
-      mainScreen: Scaffold(
+    return mainScaffold(
+      context,
+      child: Scaffold(
         body: ListView(
           children: [
             // Center(
@@ -41,23 +42,22 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
             //   )
             // ),
 
-            Center(
-              child: Padding(
-              padding: EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 0),
-                child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18))
-              ),
+          Center(
+            child: Padding(
+            padding: EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 0),
+              child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18))
             ),
+          ),
 
-            Divider(indent: 25, endIndent: 25, height: 50),
+          Divider(indent: 25, endIndent: 25, height: 50),
 
-            durationPicker(preferences.maxTime),
+          durationPicker(preferences.maxTime),
 
-            preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]),
-          ]
-        ),
-        floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
+          preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]),
+        ]
+      ),
+      floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
       ),
-      
       title: FutureBuilder(
         future: widget.trip.cityName,
         builder: (context, snapshot) => Text(
diff --git a/frontend/lib/pages/settings.dart b/frontend/lib/pages/settings.dart
index 3d5aff6..b5d3240 100644
--- a/frontend/lib/pages/settings.dart
+++ b/frontend/lib/pages/settings.dart
@@ -1,6 +1,6 @@
 import 'package:anyway/constants.dart';
+import 'package:anyway/layouts/scaffold.dart';
 import 'package:anyway/main.dart';
-import 'package:anyway/pages/base_page.dart';
 import 'package:flutter/material.dart';
 import 'package:permission_handler/permission_handler.dart';
 import 'package:shared_preferences/shared_preferences.dart';
@@ -14,42 +14,41 @@ class SettingsPage extends StatefulWidget {
   _SettingsPageState createState() => _SettingsPageState();
 }
 
-class _SettingsPageState extends State<SettingsPage> {
+class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
   @override
-  Widget build(BuildContext context) {
-    return BasePage(
-      mainScreen: ListView(
-        padding: EdgeInsets.all(15),
-        children: [
-          // First a round, centered image
-          Center(
-            child: CircleAvatar(
-              radius: 75,
-              child: Icon(Icons.settings, size: 100),
-            )
-          ),
-          Center(
-            child: Text('Global settings', style: TextStyle(fontSize: 24))
-          ),
+  Widget build (BuildContext context) => mainScaffold(
+    context,
+    child: ListView(
+      padding: EdgeInsets.all(15),
+      children: [
+        // First a round, centered image
+        Center(
+          child: CircleAvatar(
+            radius: 75,
+            child: Icon(Icons.settings, size: 100),
+          )
+        ),
+        Center(
+          child: Text('Global settings', style: TextStyle(fontSize: 24))
+        ),
 
-          Divider(indent: 25, endIndent: 25, height: 50),
+        Divider(indent: 25, endIndent: 25, height: 50),
 
-          darkMode(),
-          setLocationUsage(),
-          setDebugMode(),
+        darkMode(),
+        setLocationUsage(),
+        setDebugMode(),
 
-          Divider(indent: 25, endIndent: 25, height: 50),
+        Divider(indent: 25, endIndent: 25, height: 50),
 
-          privacyInfo(),
-        ]
-      ),
-      title: Text('Settings'),
-      helpTexts: [
-        'Settings',
-        'Preferences set in this page are global and will affect the entire application.'
-      ],
-    );
-  }
+        privacyInfo(),
+      ]
+    ),
+    title: Text('Settings'),
+    helpTexts: [
+      'Settings',
+      'Preferences set in this page are global and will affect the entire application.'
+    ],
+  );
 
   Widget setDebugMode() {
     return Row(
diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart
index a0e5905..8856047 100644
--- a/frontend/lib/structs/landmark.dart
+++ b/frontend/lib/structs/landmark.dart
@@ -70,10 +70,10 @@ final class Landmark extends LinkedListEntry<Landmark>{
       final websiteURL = json['website_url'] as String?;
       final imageURL = json['image_url'] as String?;
       final description = json['description'] as String?;
-      var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
-      final visited = json['visited'] ?? false as bool;
+      var duration = Duration(minutes: json['duration']);
+      final visited = json['visited'] ?? false;
       var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
-      
+
       return Landmark(
         uuid: uuid,
         name: name,
diff --git a/frontend/lib/structs/trip.dart b/frontend/lib/structs/trip.dart
index 8d816ca..e550540 100644
--- a/frontend/lib/structs/trip.dart
+++ b/frontend/lib/structs/trip.dart
@@ -29,6 +29,18 @@ class Trip with ChangeNotifier {
     }
   }
 
+  Future<int> landmarkPosition (Landmark landmark) async {
+    int i = 0;
+    for (Landmark l in landmarks) {
+      if (l.uuid == landmark.uuid) {
+        return i;
+      } else if (l.type != typeStart && l.type != typeFinish) {
+      i++;
+      }
+    }
+    return -1;
+  }
+
 
   Trip({
     this.uuid = 'pending',
diff --git a/frontend/lib/utils/fetch_trip.dart b/frontend/lib/utils/fetch_trip.dart
index 4fc35e2..b243f0d 100644
--- a/frontend/lib/utils/fetch_trip.dart
+++ b/frontend/lib/utils/fetch_trip.dart
@@ -1,33 +1,33 @@
 import "dart:convert";
 import "dart:developer";
-import "package:anyway/utils/load_landmark_image.dart";
 import 'package:dio/dio.dart';
 
 import 'package:anyway/constants.dart';
+import "package:anyway/utils/load_landmark_image.dart";
 import "package:anyway/structs/landmark.dart";
 import "package:anyway/structs/trip.dart";
 import "package:anyway/structs/preferences.dart";
 
 
 Dio dio = Dio(
-    BaseOptions(
-      baseUrl: API_URL_BASE,
-      connectTimeout: const Duration(seconds: 5),
-      receiveTimeout: const Duration(seconds: 120),
-      // also accept 500 errors, since we cannot rule out that the server is at fault. We still want to gracefully handle these errors
-      validateStatus: (status) => status! <= 500,
-      receiveDataWhenStatusError: true,
-      // api is notoriously slow
-      // headers: {
-      //   HttpHeaders.userAgentHeader: 'dio',
-      //   'api': '1.0.0',
-      // },
-      contentType: Headers.jsonContentType,
-      responseType: ResponseType.json,
-        
+  BaseOptions(
+    baseUrl: API_URL_BASE,
+    connectTimeout: const Duration(seconds: 5),
+    receiveTimeout: const Duration(seconds: 120),
+    // also accept 500 errors, since we cannot rule out that the server is at fault. We still want to gracefully handle these errors
+    validateStatus: (status) => status! <= 500,
+    receiveDataWhenStatusError: true,
+    // api is notoriously slow
+    // headers: {
+    //   HttpHeaders.userAgentHeader: 'dio',
+    //   'api': '1.0.0',
+    // },
+    contentType: Headers.jsonContentType,
+    responseType: ResponseType.json,    
   ),
 );
 
+
 fetchTrip(
   Trip trip,
   UserPreferences preferences,
diff --git a/frontend/lib/utils/get_first_page.dart b/frontend/lib/utils/get_first_page.dart
index e2dffd2..26f2787 100644
--- a/frontend/lib/utils/get_first_page.dart
+++ b/frontend/lib/utils/get_first_page.dart
@@ -1,11 +1,14 @@
-import 'package:anyway/pages/current_trip.dart';
-import 'package:anyway/pages/onboarding.dart';
-import 'package:anyway/structs/trip.dart';
-import 'package:anyway/utils/load_trips.dart';
+import 'package:anyway/main.dart';
 import 'package:flutter/material.dart';
 
+import 'package:anyway/structs/trip.dart';
+import 'package:anyway/utils/load_trips.dart';
+import 'package:anyway/pages/current_trip.dart';
+import 'package:anyway/pages/onboarding.dart';
+
+
 Widget getFirstPage() {
-  SavedTrips trips = SavedTrips();
+  SavedTrips trips = savedTrips;
   trips.loadTrips();
 
   return ListenableBuilder(
@@ -15,7 +18,7 @@ Widget getFirstPage() {
       if (items.isNotEmpty) {
         return TripPage(trip: items[0]);
       } else {
-        return OnboardingPage();
+        return const OnboardingPage();
       }
     }
   );
-- 
2.47.2


From 6f2f86f936a90d23ff66c3cd623bb56debd024f1 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sun, 16 Feb 2025 12:41:06 +0100
Subject: [PATCH 4/7] account for changed itineraries once landmarks are marked
 as done or deleted

---
 .../modules/current_trip_landmarks_list.dart  |  16 ++-
 .../current_trip_loading_indicator.dart       |  79 +++++------
 frontend/lib/modules/landmark_card.dart       | 127 ++++++++++--------
 .../lib/modules/step_between_landmarks.dart   |   8 ++
 frontend/lib/structs/landmark.dart            |   5 +-
 frontend/lib/structs/trip.dart                |  10 +-
 6 files changed, 135 insertions(+), 110 deletions(-)

diff --git a/frontend/lib/modules/current_trip_landmarks_list.dart b/frontend/lib/modules/current_trip_landmarks_list.dart
index 9ab4fbc..8a9f417 100644
--- a/frontend/lib/modules/current_trip_landmarks_list.dart
+++ b/frontend/lib/modules/current_trip_landmarks_list.dart
@@ -1,3 +1,5 @@
+import 'dart:developer';
+
 import 'package:flutter/material.dart';
 
 import 'package:anyway/structs/landmark.dart';
@@ -24,10 +26,16 @@ List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector
         LandmarkCard(landmark, trip),
       );
 
-      if (!landmark.visited && landmark.next != null) {
-        children.add(
-          StepBetweenLandmarks(current: landmark, next: landmark.next!)
-        );
+      if (!landmark.visited) {
+        Landmark? nextLandmark = landmark.next;
+        while (nextLandmark != null && nextLandmark.visited) {
+          nextLandmark = nextLandmark.next;
+        } 
+        if (nextLandmark != null) {
+          children.add(
+            StepBetweenLandmarks(current: landmark, next: nextLandmark!)
+          );
+        }
       }
     }
   }
diff --git a/frontend/lib/modules/current_trip_loading_indicator.dart b/frontend/lib/modules/current_trip_loading_indicator.dart
index 5eaf037..83a216a 100644
--- a/frontend/lib/modules/current_trip_loading_indicator.dart
+++ b/frontend/lib/modules/current_trip_loading_indicator.dart
@@ -1,4 +1,5 @@
-import 'package:anyway/constants.dart';
+import 'dart:async';
+
 import 'package:flutter/material.dart';
 import 'package:auto_size_text/auto_size_text.dart';
 
@@ -37,7 +38,10 @@ class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicato
       // As a gimmick, and a way to show that the app is still working, show a few loading dots
       const Align(
         alignment: Alignment.bottomCenter,
-        child: StatusText(),
+        child: Padding(
+          padding: EdgeInsets.only(bottom: 12),
+          child: StatusText(),
+        )
       )
     ],
   );
@@ -81,19 +85,19 @@ Widget loadingText(Trip trip) => FutureBuilder(
     Widget greeter;
 
     if (snapshot.hasData) {
-      greeter = AnimatedGradientText(
-        text: 'Creating your trip to ${snapshot.data}...',
+      greeter = AnimatedDotsText(
+        baseText: 'Creating your trip to ${snapshot.data}',
         style: greeterStyle,
       );
     } else if (snapshot.hasError) {
       // the exact error is shown in the central part of the trip overview. No need to show it here
-      greeter = AnimatedGradientText(
-        text: 'Error while loading trip.',
+      greeter = Text(
+        'Error while loading trip.',
         style: greeterStyle,
       );
     } else {
-      greeter = AnimatedGradientText(
-        text: 'Creating your trip...',
+      greeter = AnimatedDotsText(
+        baseText: 'Creating your trip',
         style: greeterStyle,
       );
     }
@@ -101,61 +105,44 @@ Widget loadingText(Trip trip) => FutureBuilder(
   }
 );
 
-class AnimatedGradientText extends StatefulWidget {
-  final String text;
+class AnimatedDotsText extends StatefulWidget {
+  final String baseText;
   final TextStyle style;
 
-  const AnimatedGradientText({
+  const AnimatedDotsText({
     Key? key,
-    required this.text,
+    required this.baseText,
     required this.style,
   }) : super(key: key);
 
   @override
-  _AnimatedGradientTextState createState() => _AnimatedGradientTextState();
+  _AnimatedDotsTextState createState() => _AnimatedDotsTextState();
 }
 
-class _AnimatedGradientTextState extends State<AnimatedGradientText> with SingleTickerProviderStateMixin {
-  late AnimationController _controller;
+class _AnimatedDotsTextState extends State<AnimatedDotsText> {
+  int dotCount = 0;
 
   @override
   void initState() {
     super.initState();
-    _controller = AnimationController(
-      duration: const Duration(seconds: 1),
-      vsync: this,
-    )..repeat();
-  }
-
-  @override
-  void dispose() {
-    _controller.dispose();
-    super.dispose();
+    Timer.periodic(const Duration(seconds: 1), (timer) {
+      if (mounted) {
+        setState(() {
+          dotCount = (dotCount + 1) % 4;
+          // show up to 3 dots
+        });
+      } else {
+        timer.cancel();
+      }
+    });
   }
 
   @override
   Widget build(BuildContext context) {
-    return AnimatedBuilder(
-      animation: _controller,
-      builder: (context, child) {
-        return ShaderMask(
-          shaderCallback: (bounds) {
-            return LinearGradient(
-              colors: [GRADIENT_START, GRADIENT_END, GRADIENT_START],
-              stops: [
-                _controller.value - 1.0,
-                _controller.value,
-                _controller.value + 1.0,
-              ],
-              tileMode: TileMode.mirror,
-            ).createShader(bounds);
-          },
-          child: Text(
-            widget.text,
-            style: widget.style,
-          ),
-        );
-      },
+    String dots = '.' * dotCount;
+    return Text(
+      '${widget.baseText}$dots',
+      style: widget.style,
     );
   }
 }
diff --git a/frontend/lib/modules/landmark_card.dart b/frontend/lib/modules/landmark_card.dart
index 9ef4875..8579219 100644
--- a/frontend/lib/modules/landmark_card.dart
+++ b/frontend/lib/modules/landmark_card.dart
@@ -47,32 +47,20 @@ class _LandmarkCardState extends State<LandmarkCard> {
             AspectRatio(
               aspectRatio: 3 / 4,
               child: Column(
+                crossAxisAlignment: CrossAxisAlignment.stretch,
                 children: [
                   if (widget.landmark.imageURL != null && widget.landmark.imageURL!.isNotEmpty)
                     Expanded(
                       child: CachedNetworkImage(
                         imageUrl: widget.landmark.imageURL!,
-                        placeholder: (context, url) => Center(child: CircularProgressIndicator()),
-                        errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined),
-                        fit: BoxFit.cover,
+                        placeholder: (context, url) => const Center(child: CircularProgressIndicator()),
+                        errorWidget: (context, url, error) => imagePlaceholder(widget.landmark),
+                        fit: BoxFit.cover
                       )
                     )
                   else
-                    Expanded(
-                      child: 
-                      Container(
-                        decoration: BoxDecoration(
-                          gradient: LinearGradient(
-                            begin: Alignment.topLeft,
-                            end: Alignment.bottomRight,
-                            colors: [GRADIENT_START, GRADIENT_END],
-                          ),
-                        ),
-                        child: Center(
-                          child: Icon(widget.landmark.type.icon.icon, size: 50),
-                        ),
-                      ),
-                    ),
+                    imagePlaceholder(widget.landmark),
+
                   if (widget.landmark.type != typeStart && widget.landmark.type != typeFinish)
                     Container(
                       color: PRIMARY_COLOR,
@@ -96,47 +84,54 @@ class _LandmarkCardState extends State<LandmarkCard> {
 
             // Main information, useful buttons on the right
             Expanded(
-              child: Padding(
-                padding: const EdgeInsets.all(10),
-                child: Column(
-                  crossAxisAlignment: CrossAxisAlignment.start,
-                  children: [
-                    Text(
-                      widget.landmark.name,
-                      style: Theme.of(context).textTheme.titleMedium,
-                      overflow: TextOverflow.ellipsis,
-                      maxLines: 2,
-                    ),
-                      
-                    if (widget.landmark.nameEN != null)
-                      Text(
-                        widget.landmark.nameEN!,
-                        style: Theme.of(context).textTheme.bodyMedium,
-                        maxLines: 1,
-                        overflow: TextOverflow.ellipsis,
-                      ),
-
-                    // fill the vspace
-                    const Spacer(),
-
-                    SingleChildScrollView(
-                      // allows the buttons to be scrolled
-                      scrollDirection: Axis.horizontal,
-                      child: Wrap(
-                        spacing: 10,
-                        // show the type, the website, and the wikipedia link as buttons/labels in a row
-                        children: [
-                          doneToggleButton(),
-                          if (widget.landmark.websiteURL != null)
-                            websiteButton(),
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Padding(
+                    padding: const EdgeInsets.all(10),
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Text(
+                          widget.landmark.name,
+                          style: Theme.of(context).textTheme.titleMedium,
+                          overflow: TextOverflow.ellipsis,
+                          maxLines: 2,
+                        ),
                           
-                          optionsButton()
-                        ],
-                      ),
+                        if (widget.landmark.nameEN != null)
+                          Text(
+                            widget.landmark.nameEN!,
+                            style: Theme.of(context).textTheme.bodyMedium,
+                            maxLines: 1,
+                            overflow: TextOverflow.ellipsis,
+                          ),
+                      ]
                     ),
-                  ],
-                ),
-              ),
+                  ),
+
+                  // fill the vspace
+                  const Spacer(),
+
+                  SingleChildScrollView(
+                    scrollDirection: Axis.horizontal,
+                    padding: EdgeInsets.only(left: 5, right: 5, bottom: 10),
+                    // the scroll view should be flush once the buttons are scrolled to the left
+                    // but initially there should be some padding
+                    child: Wrap(
+                      spacing: 10,
+                      // show the type, the website, and the wikipedia link as buttons/labels in a row
+                      children: [
+                        doneToggleButton(),
+                        if (widget.landmark.websiteURL != null)
+                          websiteButton(),
+                        
+                        optionsButton()
+                      ],
+                    ),
+                  ),
+                ],
+              )
             )
           ],
         )
@@ -195,3 +190,21 @@ class _LandmarkCardState extends State<LandmarkCard> {
     ],
   );
 }
+
+
+
+Widget imagePlaceholder (Landmark landmark) => Expanded(
+  child: 
+  Container(
+    decoration: const BoxDecoration(
+      gradient: LinearGradient(
+        begin: Alignment.topLeft,
+        end: Alignment.bottomRight,
+        colors: [GRADIENT_START, GRADIENT_END],
+      ),
+    ),
+    child: Center(
+      child: Icon(landmark.type.icon.icon, size: 50),
+    ),
+  ),
+);
diff --git a/frontend/lib/modules/step_between_landmarks.dart b/frontend/lib/modules/step_between_landmarks.dart
index 739f1b6..129763f 100644
--- a/frontend/lib/modules/step_between_landmarks.dart
+++ b/frontend/lib/modules/step_between_landmarks.dart
@@ -22,6 +22,14 @@ class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
   @override
   Widget build(BuildContext context) {
     int? time = widget.current.tripTime?.inMinutes;
+    
+    // since landmarks might have been marked as visited, the next landmark might not be the immediate next in the list
+    // => the precomputed trip time is not valid anymore
+    if (widget.current.next != widget.next) {
+      time = null;
+    }
+    
+    // round 0 travel time to 1 minute
     if (time != null && time < 1) {
       time = 1;
     }
diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart
index 8856047..5ef2cfd 100644
--- a/frontend/lib/structs/landmark.dart
+++ b/frontend/lib/structs/landmark.dart
@@ -29,9 +29,10 @@ final class Landmark extends LinkedListEntry<Landmark>{
   final Duration? duration;
   bool visited;
 
-  // Next node
+  // Next node is implicitly available through the LinkedListEntry mixin
   // final Landmark? next;
-  final Duration? tripTime;
+  Duration? tripTime;
+  // the trip time depends on the next landmark, so it is not final
 
 
   Landmark({
diff --git a/frontend/lib/structs/trip.dart b/frontend/lib/structs/trip.dart
index e550540..820749e 100644
--- a/frontend/lib/structs/trip.dart
+++ b/frontend/lib/structs/trip.dart
@@ -75,8 +75,16 @@ class Trip with ChangeNotifier {
     notifyListeners();
   }
 
-  void removeLandmark(Landmark landmark) {
+  void removeLandmark (Landmark landmark) async {
+    Landmark? previous = landmark.previous;
+    Landmark? next = landmark.next;
     landmarks.remove(landmark);
+    // removing the landmark means we need to recompute the time between the two adjoined landmarks
+    if (previous != null && next != null) {
+      // previous.next = next happens automatically since we are using a LinkedList
+      previous.tripTime = null;
+      // TODO
+    }
     notifyListeners();
   }
 
-- 
2.47.2


From 4ad867e609652f115cb2536c7d852b0cd1659a18 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Tue, 25 Feb 2025 19:18:44 +0100
Subject: [PATCH 5/7] revamped onboarding

---
 .vscode/launch.json                           |   2 +-
 frontend/assets/README.md                     |   2 +
 frontend/assets/cat.svg                       | 107 -----
 frontend/assets/cel-snow-globe.svg            |  79 ++++
 frontend/assets/city.svg                      | 273 -----------
 frontend/assets/cld-server.svg                |  64 +++
 frontend/assets/con-drill.svg                 |  64 +++
 frontend/assets/con-warning.svg               |  37 ++
 frontend/assets/confused.svg                  | 427 ------------------
 frontend/assets/gen-lifebelt.svg              |  76 ++++
 frontend/assets/plan.svg                      | 161 -------
 frontend/assets/terms_and_conditions.md       | 126 ++++++
 frontend/ios/fastlane/Fastfile                |   3 +-
 frontend/lib/main.dart                        |   1 -
 frontend/lib/modules/landmark_card.dart       |   1 -
 .../lib/modules/onbarding_agreement_card.dart |  97 ++++
 frontend/lib/modules/onboarding_card.dart     |  11 +-
 frontend/lib/pages/onboarding.dart            | 136 ++++--
 frontend/lib/pages/settings.dart              |   7 +-
 frontend/pubspec.lock                         |  90 ++--
 frontend/pubspec.yaml                         |   1 +
 21 files changed, 700 insertions(+), 1065 deletions(-)
 create mode 100644 frontend/assets/README.md
 delete mode 100644 frontend/assets/cat.svg
 create mode 100644 frontend/assets/cel-snow-globe.svg
 delete mode 100644 frontend/assets/city.svg
 create mode 100644 frontend/assets/cld-server.svg
 create mode 100644 frontend/assets/con-drill.svg
 create mode 100644 frontend/assets/con-warning.svg
 delete mode 100644 frontend/assets/confused.svg
 create mode 100644 frontend/assets/gen-lifebelt.svg
 delete mode 100644 frontend/assets/plan.svg
 create mode 100644 frontend/assets/terms_and_conditions.md
 create mode 100644 frontend/lib/modules/onbarding_agreement_card.dart

diff --git a/.vscode/launch.json b/.vscode/launch.json
index fa7d5d9..4454643 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -50,4 +50,4 @@
             "cwd": "${workspaceFolder}/frontend"
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/frontend/assets/README.md b/frontend/assets/README.md
new file mode 100644
index 0000000..68dd298
--- /dev/null
+++ b/frontend/assets/README.md
@@ -0,0 +1,2 @@
+## Vector assets
+As per https://www.svgrepo.com/collection/pixellove-bordered-vectors/ these icons are licensed under CC0.
diff --git a/frontend/assets/cat.svg b/frontend/assets/cat.svg
deleted file mode 100644
index f89158c..0000000
--- a/frontend/assets/cat.svg
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
-<g id="OBJECTS">
-	<g>
-		<path style="fill:#F2DBDE;" d="M381.005,363.01c-53.963,8.445-84.441,11.1-138.832,6.101
-			c-54.388-4.998-109.48-25.844-144.743-67.555c-23.468-27.759-36.728-62.943-43.732-98.613c-3.745-19.07-5.754-39.21,0.433-57.635
-			c7.513-22.378,26.565-39.569,48.136-49.156c21.572-9.589,45.552-12.365,69.151-12.944c47.753-1.172,95.706,6.26,140.863,21.831
-			c35.603,12.277,69.954,29.937,96.972,56.171c27.019,26.233,46.213,61.723,47.963,99.341
-			C458.967,298.17,438.434,354.022,381.005,363.01z"/>
-		<g>
-			<path style="fill:#F2BFC6;" d="M314.479,248.209c-22.398,36.41-29.246,81.831-19.597,123.401
-				c27.302-0.242,52.026-3.263,86.124-8.6c57.429-8.989,77.961-64.84,76.211-102.458c-1.503-32.308-15.881-63.041-37.024-87.694
-				C375.546,184.337,337.241,211.21,314.479,248.209z"/>
-			<path style="fill:#F2BFC6;" d="M60.074,229.111c2.232,7.566,4.802,15.029,7.749,22.32c40.138-5.931,78.066-26.379,104.834-56.907
-				c26.459-30.176,41.716-69.876,42.677-109.969c-14.6-1.246-29.267-1.705-43.916-1.345c-11.908,0.292-23.911,1.147-35.655,3.151
-				C136.569,142.478,107.155,198.423,60.074,229.111z"/>
-			<path style="fill:#F2BFC6;" d="M365.131,128.557c-16.748-9.529-34.631-17.233-52.85-23.516
-				c-6.45-2.224-12.962-4.262-19.517-6.153c-1.712,23.304-4.543,46.555-11.914,68.659c-9.236,27.692-26.464,53.808-52.01,67.931
-				c-22.973,12.7-50.376,14.689-74.443,25.169c-21.624,9.417-39.587,25.305-54.36,43.893c8.346,9.381,17.714,17.663,27.862,24.902
-				c16.736-21.461,41.874-37.166,67.161-48.559c35.578-16.03,74.129-26.682,105.739-49.566
-				C334.357,207.023,357.577,169.22,365.131,128.557z"/>
-		</g>
-	</g>
-	<ellipse style="opacity:0.15;fill:#2D3038;" cx="250.223" cy="394.224" rx="109.236" ry="18.917"/>
-	<g>
-		<path style="fill:#2D3038;" d="M305.132,388.442c-0.168,1.158-0.626,2.243-1.458,3.061c-1.863,1.832-4.823,1.724-7.427,1.538
-			c-17.939-1.285-36.017-0.625-53.815,1.965c-7.053,3.155-16.423,3.233-25.275,2.004c-8.853-1.231-17.514-3.684-26.397-4.661
-			c-8.885-0.976-21.867-0.33-26.499,2.758c0,0-7.266,3.996-12.907,12.021c-3.367,4.789-4.105,11.306-2.377,16.899
-			c2.452,7.945,10.312,13.334,18.475,14.912c8.163,1.579,16.603-0.053,24.6-2.327c22.82-6.49,43.805-18.134,66.018-26.468
-			c22.213-8.334,47.017-13.282,69.546-5.844c3.96,1.306,7.879,3.033,10.941,5.866c3.062,2.832,5.173,6.927,4.813,11.081
-			c-0.464,5.356-4.97,9.719-10.061,11.444c-5.092,1.726-10.658,1.275-15.953,0.346c-5.296-0.93-10.554-2.17-15.926-2.414
-			c-20.08-0.909-38.455,4.247-56.124,10.857c-17.669,6.608-35.096,14.21-53.56,18.085c-18.463,3.874-35.807,8.106-51.682-4.186
-			c-20.345-15.753-19.603-41.137-8.091-63.296c5.521-10.629,12.589-18.637,19.416-27.732c-1.72-12.542-6.898-24.945-9.467-37.525
-			c-4.135-20.25-1.309-41.854,7.666-61.314c5.614-15.439,11.257-30.942,19.093-45.38c7.835-14.438,18.007-27.88,31.297-37.536
-			c13.289-9.656,29.927-15.279,46.993-13.222c7.787-8.403,16.038-16.377,24.703-23.871c-1.319-7.29-1.183-14.637,0.584-20.961
-			c-4.077-8.872-8.2-17.907-9.54-27.579c-0.835-6.027-0.441-12.408,1.577-17.991c1.878-5.198,8.452-6.799,12.542-3.08
-			c6.673,6.07,12.683,12.869,17.891,20.235c18.398-4.802,38.164-4.231,56.264,1.583c6.473-8.017,14.398-14.861,23.286-20.075
-			c2.366-1.388,5.533-2.613,7.657-0.875c1.683,1.377,1.736,3.89,1.592,6.059c-0.815,12.217-3.418,24.313-8.016,36.577
-			c4.862,15.779,0.82,33.862-9.812,46.412c-2.168,11.956,1.193,24.438,2.504,36.665c2.294,21.385-1.98,43.411-12.271,62.744
-			c-2.4,4.508-5.754,8.444-9.863,11.477c-1.71,1.263-3.38,2.581-5.006,3.951c-5.172,20.881-10.139,41.311-15.351,62.281
-			c2.061,7.78,4.487,15.496,7.272,23.126c3.209-0.899,6.478-1.696,9.816-1.809c3.896-0.132,7.942,0.744,11.024,3.131
-			c2.308,1.785,3.979,4.375,4.658,7.212c0.484,2.028,0.445,4.26-0.563,6.086c-0.663,1.203-1.81,2.171-3.102,2.583
-			c0.454,1.78,0.565,3.616,0.106,5.385c-0.778,3.004-3.622,5.6-6.675,5.375c-0.047,0.112-0.097,0.223-0.151,0.333
-			c-0.979,1.985-3.08,3.228-5.239,3.714c-2.063,0.464-4.207,0.333-6.319,0.174c-0.138,0.225-0.3,0.437-0.489,0.633
-			c-1.556,1.603-4.16,1.338-6.346,0.87c-3.015-0.645-6.04-1.471-8.688-3.051c-2.647-1.583-4.906-4.013-5.707-6.991
-			c-1.237-4.607,2.111-10.097,0.151-14.313c-3.538-7.609-7.733-14.893-12.004-22.126c-8.712,7.077-18.162,13.242-28.147,18.367
-			c6.95-0.974,14.248-1.345,21.476-0.293c3.273,0.475,6.596,1.283,9.285,3.208c2.689,1.924,4.631,5.173,4.214,8.453
-			c-0.34,2.664-2.596,5.054-5.156,5.449"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M151.465,379.089
-			c0.578-3.877,0.614-7.729,0.28-11.566"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M296.431,98.602
-			c1.739,2.591,3.381,5.247,4.918,7.962"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M273.736,153.553
-			c-0.645-1.929-1.188-3.891-1.625-5.865"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M295.23,106.811
-			c-4.87-7.904-10.55-15.309-16.923-22.061c-1.834-1.943-4.156-3.987-6.799-3.598c-2.928,0.431-4.574,3.626-5.147,6.53
-			c-1.629,8.254,1.474,16.627,4.521,24.47"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M352.846,98.327
-			c1.084,0.372,2.162,0.763,3.232,1.174"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M363.545,168.179
-			c-1.077,1.107-2.211,2.161-3.399,3.155"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M295.583,130.136
-			c3.86-4.907,10.772-7.181,16.791-5.521c6.019,1.659,10.791,7.151,11.446,13.054c-4.594,3.601-11.6,3.717-16.311,0.268
-			c-3.162-2.315-5.105-6.101-5.423-9.993"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M363.109,126.785
-			c-1.79-2.631-5.159-4.002-8.321-3.646c-3.162,0.356-6.042,2.317-7.787,4.979c-1.743,2.662-2.395,5.96-1.828,9.854
-			c4.738,1.952,10.727,0.164,13.621-4.066c1.462-2.137,2.057-4.785,1.832-7.36"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M350.957,171.048
-			c-4.278,4.378-10.749,6.497-16.787,5.499"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M338.68,282.717
-			c-5.42,4.867-10.31,10.327-14.541,16.258"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M333.834,368.351
-			c0.757,2.017,1.54,4.028,2.348,6.032c2.26-0.589,4.541-1.183,6.876-1.268c2.333-0.084,4.757,0.381,6.656,1.74
-			c1.559,1.116,2.664,2.753,3.552,4.452c0.261,0.499,0.505,1.013,0.727,1.536"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M317.138,283.315
-			c0.476,18.805,3.038,37.553,7.633,55.961"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M337.823,376.837
-			c2.877-0.595,5.878,0.99,7.67,3.316c1.791,2.327,2.567,5.273,3.025,8.174c0.191,1.214,0.327,2.48,0.209,3.695"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M327.236,380.633
-			c3.086-0.38,6.102,1.606,7.733,4.252c1.632,2.645,2.112,5.835,2.285,8.939c0.04,0.721,0.054,1.476-0.027,2.204"/>
-		<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M305.059,385.808
-			c-0.036-0.193-0.079-0.385-0.128-0.573c-1.058-4.111-4.728-7.422-8.927-8.052"/>
-		<g>
-			<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M250.442,264.812
-				c-1.67-3.125-3.183-6.325-4.488-9.622c-5.098-12.883-6.92-27.047-5.248-40.801"/>
-			<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M302.266,351.248
-				c-7.667-12.944-15.022-25.405-19.496-39.762"/>
-			<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M272.435,372.065
-				c-3.368,0.554-6.637,1.226-9.757,1.918c10.852-22.715,21.971-46.794,19.913-71.883c-0.826-10.055-4.036-20.316-11.156-27.463
-				c-8.522-8.553-21.576-11.406-33.547-9.827c-22.022,2.903-41.327,20.57-46.167,42.248"/>
-		</g>
-		<g>
-			<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M328.579,152.076
-				c1.379-0.341,2.796,0.501,3.736,1.565c0.942,1.065,1.588,2.366,2.551,3.41c0.963,1.044,2.43,1.826,3.784,1.398
-				c1.002-0.317,1.702-1.217,2.207-2.139c0.504-0.921,0.888-1.923,1.572-2.721c1.237-1.447,3.432-1.978,5.192-1.258"/>
-			<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M360.735,158.173
-				c-2.16,5.007-7.325,8.57-12.773,8.812c-1.946,0.086-3.967-0.245-5.593-1.317c-1.872-1.234-2.979-3.253-3.85-5.361
-				c-0.089,1.146-0.496,2.29-1.133,3.25c-1.229,1.854-3.175,3.116-5.189,4.059c-3.3,1.546-7.007,2.373-10.616,1.879
-				c-3.611-0.495-7.099-2.413-9.07-5.477"/>
-			<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M338.276,158.534
-				c0,0,0.176,1.073,0.244,1.773"/>
-		</g>
-	</g>
-</g>
-</svg>
diff --git a/frontend/assets/cel-snow-globe.svg b/frontend/assets/cel-snow-globe.svg
new file mode 100644
index 0000000..bf299ba
--- /dev/null
+++ b/frontend/assets/cel-snow-globe.svg
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>cel-snow-globe</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="SLICES-64px" transform="translate(-450.000000, 0.000000)">
+
+</g>
+        <g id="ICONS" transform="translate(-445.000000, 5.000000)">
+            <g id="cel-snow-globe" transform="translate(450.000000, 2.000000)">
+                <path d="M46,44 C48.209,44 50,45.791 50,48 L50,52 L2,52 L2,48 C2,45.791 3.791,44 6,44 L46,44 Z" id="Fill-1055" fill="#EEC261">
+
+</path>
+                <path d="M7.2402,44.002 C2.7562,39.33 0.0002,32.987 0.0002,26 C0.0002,11.641 11.6402,0 26.0002,0 C40.3592,0 52.0002,11.641 52.0002,26 C52.0002,32.986 49.2442,39.33 44.7602,44.001 L7.2402,44.002 Z" id="Fill-1056" fill="#B6E0F2">
+
+</path>
+                <path d="M38,37 C38,33.134 34.866,30 31,30 C27.134,30 24,33.134 24,37 C24,40.866 27.134,44 31,44 C34.866,44 38,40.866 38,37" id="Fill-1057" fill="#E9EFFA">
+
+</path>
+                <path d="M26,25 C26,22.238 28.239,20 31,20 C33.761,20 36,22.238 36,25 C36,27.762 33.761,30 31,30 C28.239,30 26,27.762 26,25" id="Fill-1058" fill="#E9EFFA">
+
+</path>
+                <path d="M38,37 C38,33.134 34.866,30 31,30 C27.134,30 24,33.134 24,37 C24,40.866 27.134,44 31,44 C34.866,44 38,40.866 38,37 Z" id="Stroke-1059" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M26,25 C26,22.238 28.239,20 31,20 C33.761,20 36,22.238 36,25 C36,27.762 33.761,30 31,30 C28.239,30 26,27.762 26,25 Z" id="Stroke-1060" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M46,44 C48.209,44 50,45.791 50,48 L50,52 L2,52 L2,48 C2,45.791 3.791,44 6,44 L46,44 Z" id="Stroke-1061" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M7.2402,44.002 C2.7562,39.33 0.0002,32.987 0.0002,26 C0.0002,11.641 11.6402,0 26.0002,0 C40.3592,0 52.0002,11.641 52.0002,26 C52.0002,32.986 49.2442,39.33 44.7602,44.001" id="Stroke-1062" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M8,24 C8,14.059 16.059,6 26,6" id="Stroke-1063" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M20,28 L26.061,32.04" id="Stroke-1064" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M42,28 L35.939,32.04" id="Stroke-1065" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M42,25 L42,28" id="Stroke-1066" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M45,28 L42,28" id="Stroke-1067" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M20,25 L20,28" id="Stroke-1068" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M17,28 L20,28" id="Stroke-1069" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M10.02,31.0098 C10.02,31.5688 9.568,32.0208 9.01,32.0208 C8.452,32.0208 8,31.5688 8,31.0098 C8,30.4518 8.452,29.9998 9.01,29.9998 C9.568,29.9998 10.02,30.4518 10.02,31.0098 Z" id="Stroke-1070" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M22.02,15.0098 C22.02,15.5688 21.568,16.0208 21.01,16.0208 C20.452,16.0208 20,15.5688 20,15.0098 C20,14.4518 20.452,13.9998 21.01,13.9998 C21.568,13.9998 22.02,14.4518 22.02,15.0098 Z" id="Stroke-1071" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M44.02,17.0098 C44.02,17.5688 43.568,18.0208 43.01,18.0208 C42.452,18.0208 42,17.5688 42,17.0098 C42,16.4518 42.452,15.9998 43.01,15.9998 C43.568,15.9998 44.02,16.4518 44.02,17.0098 Z" id="Stroke-1072" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M18.02,37.0098 C18.02,37.5688 17.568,38.0208 17.01,38.0208 C16.452,38.0208 16,37.5688 16,37.0098 C16,36.4518 16.452,35.9998 17.01,35.9998 C17.568,35.9998 18.02,36.4518 18.02,37.0098 Z" id="Stroke-1073" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M36.02,9.0098 C36.02,9.5688 35.568,10.0208 35.01,10.0208 C34.452,10.0208 34,9.5688 34,9.0098 C34,8.4518 34.452,7.9998 35.01,7.9998 C35.568,7.9998 36.02,8.4518 36.02,9.0098 Z" id="Stroke-1074" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/frontend/assets/city.svg b/frontend/assets/city.svg
deleted file mode 100644
index 8f4bf7a..0000000
--- a/frontend/assets/city.svg
+++ /dev/null
@@ -1,273 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 viewBox="0 0 1000 700" style="enable-background:new 0 0 1000 700;" xml:space="preserve">
-<g id="Shadow">
-	<g style="opacity:0.1;">
-		<path style="fill:#38415C;" d="M186.919,556.734c0,0.331,0.541,0.599,1.208,0.599c0.667,0,1.208-0.268,1.208-0.599
-			c0-0.331-0.541-0.599-1.208-0.599C187.46,556.135,186.919,556.403,186.919,556.734z"/>
-		<path style="fill:#38415C;" d="M957.699,446.328h-12.196h-37.267h-8.131h-4.525h-22.106h-29.729h-8.01h-8.921h-7.462H777.69h-5.38
-			h-8.517h-13.921h-24.898h-0.367h-35.201h-33.29h-13.405h-8.642h-18.387h-20.084H584.19h-2.542h-5.421h-37.944h-7.453h-2.757
-			h-2.757h-1.428h-8.748h-5.514h-10.175h-0.905h-4.609h-10.175h-5.514h-10.175h-2.757h-2.757h-27.938h-8.05h-29.96h-6.713h-18.964
-			h-11.234h-48.644h-12.099h-10.229h-20.764h-12.382h-3.512h-23.242h-5.943h-13.266h-10.795h-35.413h-16.467h-4.656h-8.696h-25.877
-			H89.054h-4.763H72.026h-7.508H53.821H42.302v9.376h11.519v6.41h10.696v6.835h19.774v2.177h20.658v9.405h17.084v-5.919h11.557
-			v10.475h3.789v11.69h11.18v9.823h-4.017v1.763h7.066v4.785h23.433v28.254h-1.845v1.897h4.028v2.429h4.636v0.913v2.777v2.41h5.594
-			v4.306h0.673l0,0h0.673v-4.306h3.015l1.823-2.41h12.206v-3.69h31.948V543.3h4.028v-1.897h-1.845V484.37h15.302v40.617h1.509v3.023
-			h2.811v10.012h1.016v-10.012h2.287v7.997h1.017v-7.997h4.828v-3.023h6.098v-10.569h11.445v-0.743h-1.492v-2.116h7.56v32.974
-			h-1.078v0.849h7.678v5.101h-0.992v0.817h7.047v2.933h-1.099v0.627h3.502v2.77h3.348v5.513h0.402h0.398h0.314v-5.513h1.354v9.889
-			h0.402h0.399h0.314v-9.889h0.451h2.897v-2.77h3.034v-0.627h-0.632v-2.933h7.047v-0.817h-0.992v-5.101h7.678v-0.849h-1.078v-43.096
-			h23.505v-5.982h8.399v31.88h-4.954v0.806h4.954v1.443h6.279v2.37h30.344v27.318h7.165v21.803h13.871V593h1.952v-11.927h4.298
-			v9.528h1.952v-9.528h21.941v-12.964h3.982v-8.839h11.148v-32.999h4.318v-7.629l6.342,0.769v1.742h5.514v-1.073l10.175,1.234v1.969
-			h5.514v-1.3l9.332,1.131v9.523h2.491v16.539h11.982v6.297h6.46v5.29h2.267v9.068h0.586v-9.068h2.267v-5.29h6.46v-6.297h12.075
-			v-16.539h2.399v-45.67l5.467,13.925h5.729v12.219h-2.645v0.527h31.278v6.75h-3.52v0.763h-1.791v2.08h8.284v2.313h-1.087v0.668
-			h18.198v-0.668h-1.087v-2.313h23.966c0.802,1.935,2.023,3.811,3.668,5.596l-3.992,0.913c-0.688-0.732-2.184-1.239-3.92-1.239
-			c-2.388,0-4.324,0.96-4.324,2.143c0,1.183,1.936,2.143,4.324,2.143c2.388,0,4.324-0.96,4.324-2.143
-			c0-0.239-0.08-0.468-0.225-0.683l4.015-0.919c2.595,2.749,6.165,5.281,10.623,7.491c0.352,0.174,0.709,0.346,1.069,0.515
-			l-3.154,1.668c-0.76-0.329-1.753-0.528-2.841-0.528c-2.388,0-4.324,0.959-4.324,2.143s1.936,2.143,4.324,2.143
-			c2.388,0,4.324-0.959,4.324-2.143c0-0.559-0.432-1.068-1.139-1.449l3.16-1.671c5.36,2.471,11.576,4.337,18.308,5.527l-1.744,2.453
-			c-0.378-0.054-0.777-0.083-1.19-0.083c-2.388,0-4.324,0.96-4.324,2.143c0,1.183,1.936,2.143,4.324,2.143
-			c2.388,0,4.324-0.96,4.324-2.143c0-0.895-1.107-1.662-2.68-1.982l1.743-2.451c5.551,0.953,11.445,1.449,17.493,1.449
-			c0.498,0,0.995-0.003,1.491-0.01l0.198,3.017c-2.096,0.148-3.707,1.041-3.707,2.121c0,1.183,1.936,2.143,4.324,2.143
-			c2.388,0,4.324-0.96,4.324-2.143c0-1.184-1.936-2.143-4.324-2.143c-0.046,0-0.091,0.001-0.137,0.002l-0.197-3.004
-			c2.456-0.044,4.881-0.173,7.265-0.378l-2.223,24.735l79.948-8.225v-43.336h13.883v22.309h24.985v8.902h1.355v-8.902h2.795v16.446
-			h1.355v-16.446h3.219v11.855h1.355v-11.855h4.235v-54.059h12.874V506.6h2.033v3.715h2.033v2.582h14.483v-2.582h2.033V506.6h7.369
-			v1.594h3.557V506.6h1.259v4.262h5.082V506.6h1.452l3.161-11.593h11.528v5.526h0.762v-5.526h4.32v6.746h0.762v-6.746h6.25v-1.567
-			h-1.592v-17.317h12.874l1.507-4.997h10.931v-9.012h11.954v-6.86h12.196V446.328z M653.829,518.335l-11.117,0.179v-7.937h2.055
-			v-0.76h-2.055v-0.593l13.295,2.426c-1.417,1.94-2.19,4.031-2.19,6.21C653.816,518.019,653.821,518.177,653.829,518.335z
-			 M689.289,499.58c-4.354,0.083-8.516,0.542-12.36,1.312l-5.314-6.414v-0.42h5.082v4.786h5.082v-4.786h7.148L689.289,499.58z
-			 M702.329,517.554l-8.713,0.14c-0.026-0.114-0.079-0.224-0.155-0.328l9.073-2.076L702.329,517.554z M666.025,494.058v0.401
-			c-0.325,0.085-0.657,0.163-0.979,0.251l-0.713-0.651H666.025z M666.025,495.263v0.341l-0.291-0.266
-			C665.83,495.311,665.929,495.289,666.025,495.263z M666.025,496.603v2.241h2.454l3.554,3.247c-2.98,0.871-5.693,1.943-8.062,3.179
-			l-10.904-5.064c0.33-0.173,0.666-0.344,1.007-0.513c3.276-1.624,6.914-3.003,10.823-4.12L666.025,496.603z M672.377,502.405
-			l15.07,13.768l-22.95-10.659C666.813,504.306,669.465,503.258,672.377,502.405z M669.572,498.844h2.043v-3.739l4.87,5.877
-			c-1.242,0.259-2.449,0.55-3.618,0.872L669.572,498.844z M691.664,494.058v4.786h12.332l-1.224,1.721
-			c-3.776-0.648-7.828-1.001-12.044-1.001c-0.32,0-0.64,0.002-0.959,0.006l-0.361-5.512H691.664z M703.939,499.641l-0.101,1.127
-			c-0.206-0.039-0.404-0.087-0.612-0.124L703.939,499.641z M702.896,511.25l-8.307,4.394l8.619-7.874L702.896,511.25z
-			 M702.863,511.616l-0.306,3.407l-9.299,2.127c-0.053-0.046-0.11-0.09-0.172-0.133l0.598-0.547L702.863,511.616z M693.364,518.468
-			l8.74,1.595l-0.252,2.801l-8.846-4.108C693.147,518.667,693.268,518.571,693.364,518.468z M693.53,518.245
-			c0.056-0.1,0.091-0.205,0.102-0.312l8.676-0.14l-0.182,2.021L693.53,518.245z M656.116,486.551l-11.415-10.428h11.415V486.551z
-			 M656.116,487.55v4.746h-1.779v1.763h8.903l0.969,0.885c-4.029,1.15-7.778,2.571-11.154,4.243
-			c-0.352,0.175-0.698,0.352-1.039,0.53l-3.311-1.538c0.63-0.372,1.01-0.852,1.01-1.376c0-1.184-1.936-2.143-4.324-2.143
-			c-1.018,0-1.941,0.182-2.68,0.473v-5.035h2.055v-0.76h-2.055v-9.479h2.055v-0.76h-2.055v-2.977h0.897L656.116,487.55z
-			 M642.711,500.338h2.055v-0.76h-2.055v-1.104c0.739,0.292,1.662,0.473,2.68,0.473c1.158,0,2.209-0.226,2.985-0.593l3.31,1.537
-			c-3.677,1.959-6.684,4.15-8.975,6.503V500.338z M642.711,508.163c2.337-2.844,5.703-5.479,10.027-7.784l10.906,5.065
-			c-3.215,1.722-5.771,3.749-7.47,5.983l-13.463-2.457V508.163z M664.17,505.688l24.004,11.148l0.198,0.181
-			c-0.107,0.074-0.2,0.152-0.279,0.235l-31.242-5.701C658.515,509.362,661.02,507.375,664.17,505.688z M673.21,502.168
-			c1.146-0.316,2.33-0.602,3.548-0.855l12.647,15.264c-0.111,0.028-0.218,0.06-0.32,0.094L673.21,502.168z M677.203,501.222
-			c3.766-0.755,7.844-1.204,12.11-1.286l1.082,16.492c-0.187,0.011-0.369,0.03-0.544,0.057L677.203,501.222z M689.793,499.928
-			c0.311-0.004,0.623-0.006,0.935-0.006c4.131,0,8.103,0.346,11.804,0.981l-11.067,15.563c-0.19-0.025-0.388-0.04-0.591-0.045
-			L689.793,499.928z M702.985,500.982c0.278,0.05,0.543,0.112,0.818,0.165l-0.497,5.535l-10.935,9.99
-			c-0.142-0.048-0.294-0.09-0.453-0.126L702.985,500.982z M692.678,518.929l9.146,4.247l-0.629,7.002l-9.143-11.035
-			C692.279,519.085,692.49,519.013,692.678,518.929z M656.683,511.774l31.244,5.702c-0.056,0.1-0.091,0.204-0.102,0.312
-			l-33.276,0.536c-0.008-0.154-0.012-0.309-0.012-0.464C654.537,515.724,655.295,513.675,656.683,511.774z M687.841,518.026
-			c0.026,0.114,0.079,0.224,0.155,0.328l-30.225,6.916c-1.892-2.059-3.018-4.325-3.204-6.708L687.841,518.026z M688.199,518.57
-			c0.106,0.092,0.231,0.178,0.373,0.257l-22.753,12.035c-3.243-1.527-5.915-3.348-7.845-5.376L688.199,518.57z M688.923,518.989
-			c0.188,0.074,0.394,0.137,0.616,0.186l-11.067,15.563c-4.604-0.824-8.776-2.098-12.301-3.714L688.923,518.989z M689.992,519.254
-			c0.19,0.024,0.388,0.04,0.591,0.045l1.082,16.493c-0.311,0.004-0.623,0.006-0.936,0.006c-4.131,0-8.102-0.346-11.804-0.98
-			L689.992,519.254z M691.063,519.291c0.187-0.011,0.369-0.03,0.544-0.057l9.537,11.51l-0.39,4.342
-			c-2.753,0.394-5.632,0.641-8.61,0.697L691.063,519.291z M640.035,523.229h7.987v-2.08h-1.791v-0.763h-3.52v-1.635l11.136-0.179
-			c0.189,2.432,1.339,4.745,3.27,6.846l-13.578,3.106C641.982,526.835,640.816,525.059,640.035,523.229z M654.074,536.027
-			c-4.336-2.149-7.809-4.612-10.333-7.285l13.579-3.107c1.969,2.07,4.697,3.929,8.007,5.487l-10.218,5.404
-			C654.761,536.362,654.415,536.196,654.074,536.027z M655.459,536.689l10.219-5.405c3.597,1.65,7.855,2.95,12.553,3.791
-			l-4.97,6.989C666.716,540.907,660.672,539.092,655.459,536.689z M690.728,543.552c-5.882,0-11.614-0.483-17.013-1.409l4.97-6.989
-			c3.776,0.648,7.828,1.001,12.043,1.001c0.321,0,0.64-0.002,0.959-0.006l0.485,7.393
-			C691.692,543.549,691.211,543.552,690.728,543.552z M692.653,543.535l-0.485-7.395c2.956-0.057,5.813-0.299,8.553-0.681
-			l-0.69,7.679C697.611,543.354,695.148,543.49,692.653,543.535z"/>
-	</g>
-</g>
-<g id="Object">
-	<g style="opacity:0.3;">
-		<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="207.5072" y1="393.376" x2="207.5072" y2="229.7061">
-			<stop  offset="0" style="stop-color:#403E40"/>
-			<stop  offset="0.1275" style="stop-color:#4E4D4E"/>
-			<stop  offset="0.3124" style="stop-color:#5A5A5A"/>
-			<stop  offset="0.5479" style="stop-color:#626262"/>
-			<stop  offset="1" style="stop-color:#646464"/>
-		</linearGradient>
-		<polygon style="fill:url(#SVGID_1_);" points="175.04,393.376 239.974,393.376 239.974,259.43 241.819,259.43 241.819,255.601 
-			237.792,255.601 237.792,250.701 205.844,250.701 205.844,243.255 193.638,243.255 191.815,238.393 188.799,238.393 
-			188.799,229.706 188.126,229.706 187.454,229.706 187.454,238.393 181.859,238.393 181.859,243.255 181.859,248.859 
-			181.859,250.701 177.223,250.701 177.223,255.601 173.195,255.601 173.195,259.43 175.04,259.43 		"/>
-		
-			<linearGradient id="SVGID_00000000931258187104496080000017865145222397382034_" gradientUnits="userSpaceOnUse" x1="188.1266" y1="229.7061" x2="188.1266" y2="227.2891">
-			<stop  offset="0" style="stop-color:#403E40"/>
-			<stop  offset="0.1275" style="stop-color:#4E4D4E"/>
-			<stop  offset="0.3124" style="stop-color:#5A5A5A"/>
-			<stop  offset="0.5479" style="stop-color:#626262"/>
-			<stop  offset="1" style="stop-color:#646464"/>
-		</linearGradient>
-		<path style="fill:url(#SVGID_00000000931258187104496080000017865145222397382034_);" d="M189.335,228.498
-			c0-0.668-0.541-1.209-1.209-1.209c-0.667,0-1.208,0.541-1.208,1.209c0,0.667,0.541,1.208,1.208,1.208
-			C188.794,229.706,189.335,229.165,189.335,228.498z"/>
-		
-			<linearGradient id="SVGID_00000036247364810958532620000001993945857249512106_" gradientUnits="userSpaceOnUse" x1="508.9194" y1="421.4165" x2="508.9194" y2="155.3276">
-			<stop  offset="0" style="stop-color:#403E40"/>
-			<stop  offset="0.1275" style="stop-color:#4E4D4E"/>
-			<stop  offset="0.3124" style="stop-color:#5A5A5A"/>
-			<stop  offset="0.5479" style="stop-color:#626262"/>
-			<stop  offset="1" style="stop-color:#646464"/>
-		</linearGradient>
-		<polygon style="fill:url(#SVGID_00000036247364810958532620000001993945857249512106_);" points="777.689,401.218 777.689,221.14 
-			697.741,204.545 706.501,401.218 471.904,401.218 471.904,289.958 467.586,289.958 467.586,223.38 456.438,223.38 
-			456.438,205.547 452.456,205.547 452.456,179.391 430.514,179.391 430.514,160.168 428.562,160.168 428.562,179.391 
-			424.264,179.391 424.264,155.328 422.311,155.328 422.311,179.391 408.44,179.391 408.44,223.38 401.275,223.38 401.275,289.958 
-			395.133,289.958 395.133,401.218 332.748,401.218 332.748,253.114 333.825,253.114 333.825,251.402 326.147,251.402 
-			326.147,241.111 327.14,241.111 327.14,239.463 320.092,239.463 320.092,233.547 320.725,233.547 320.725,232.282 317.69,232.282 
-			317.69,226.693 314.794,226.693 314.343,226.693 314.343,206.742 314.029,206.742 313.63,206.742 313.228,206.742 
-			313.228,226.693 311.874,226.693 311.874,215.571 311.56,215.571 311.161,215.571 310.759,215.571 310.759,226.693 
-			307.411,226.693 307.411,232.282 303.909,232.282 303.909,233.547 305.009,233.547 305.009,239.463 297.962,239.463 
-			297.962,241.111 298.954,241.111 298.954,251.402 291.276,251.402 291.276,253.114 292.354,253.114 292.354,401.218 
-			84.29,401.218 84.29,421.417 933.548,421.417 933.548,401.218 		"/>
-	</g>
-	
-		<linearGradient id="SVGID_00000121963338060960119620000016097684000583641491_" gradientUnits="userSpaceOnUse" x1="499.6613" y1="451.2495" x2="499.6613" y2="202.0752">
-		<stop  offset="0.0815" style="stop-color:#403E40"/>
-		<stop  offset="0.4715" style="stop-color:#444244"/>
-		<stop  offset="0.8768" style="stop-color:#504F50"/>
-		<stop  offset="1" style="stop-color:#555455"/>
-	</linearGradient>
-	<path style="fill:url(#SVGID_00000121963338060960119620000016097684000583641491_);" d="M918.278,419.4v-18.183h-25.56
-		l-9.674-71.571h-1.452v-8.598h-5.082v8.598h-1.259v-3.216h-3.557v3.216h-7.369v-7.496h-2.033v-5.209h-14.483v5.209h-2.033v7.496
-		h-2.033v42.986h-12.874V263.564h-4.235v-23.92h-1.355v23.92h-3.219v-33.181h-1.355v33.181h-2.795v-17.961h-1.355v17.961h-24.985
-		v77.418h-27.78v50.154h-25.944l-20.601-37.972c3.473-2,6.738-4.405,9.735-7.193l4.225,4.508c-0.907,0.793-1.481,1.957-1.481,3.256
-		c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
-		c-0.916,0-1.764,0.285-2.463,0.771l-4.255-4.54c0.36-0.341,0.717-0.687,1.069-1.039c4.458-4.459,8.028-9.568,10.623-15.114
-		l4.705,2.172c-0.086,0.339-0.131,0.693-0.131,1.059c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324
-		c0-2.388-1.936-4.324-4.324-4.324c-1.852,0-3.432,1.165-4.048,2.803l-4.648-2.146c2.866-6.273,4.489-13.092,4.744-20.153
-		l5.065,0.165c0.062,2.334,1.972,4.207,4.321,4.207c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
-		c-2.266,0-4.123,1.743-4.308,3.961l-5.064-0.165c0.013-0.496,0.021-0.993,0.021-1.491c0-6.303-1.088-12.438-3.173-18.192
-		l4.231-1.558c0.664,1.533,2.191,2.606,3.968,2.606c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
-		c-2.388,0-4.324,1.936-4.324,4.324c0,0.44,0.066,0.866,0.189,1.267l-4.229,1.557c-2.41-6.464-6.085-12.437-10.898-17.611
-		l3.31-3.102c0.776,0.741,1.827,1.197,2.985,1.197c2.388,0,4.324-1.935,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
-		c-2.388,0-4.324,1.936-4.324,4.324c0,1.057,0.38,2.025,1.01,2.776l-3.31,3.102c-0.341-0.36-0.687-0.717-1.039-1.069
-		c-5.012-5.013-10.848-8.903-17.201-11.546l1.821-4.434c0.413,0.131,0.853,0.203,1.309,0.203c2.388,0,4.324-1.936,4.324-4.324
-		c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.936-4.324,4.324c0,1.762,1.054,3.276,2.566,3.95l-1.816,4.423
-		c-5.685-2.304-11.775-3.615-18.057-3.842l0.197-6.06c0.046,0.001,0.091,0.003,0.137,0.003c2.388,0,4.324-1.936,4.324-4.324
-		c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.936-4.324,4.324c0,2.179,1.611,3.98,3.707,4.279l-0.198,6.086
-		c-0.496-0.014-0.993-0.021-1.491-0.021c-6.048,0-11.942,1.001-17.493,2.925l-1.743-4.946c1.573-0.647,2.68-2.193,2.68-4
-		c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.936-4.324,4.324c0,2.388,1.936,4.324,4.324,4.324
-		c0.413,0,0.812-0.059,1.19-0.167l1.744,4.948c-6.732,2.401-12.948,6.166-18.308,11.152l-3.16-3.372
-		c0.707-0.77,1.139-1.796,1.139-2.923c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.935-4.324,4.324
-		c0,2.388,1.936,4.324,4.324,4.324c1.088,0,2.081-0.402,2.841-1.065l3.154,3.366c-0.36,0.341-0.717,0.688-1.069,1.04
-		c-4.458,4.458-8.028,9.568-10.623,15.114l-4.015-1.854c0.146-0.433,0.225-0.896,0.225-1.377c0-2.388-1.936-4.324-4.324-4.324
-		c-2.388,0-4.324,1.936-4.324,4.324c0,2.388,1.936,4.324,4.324,4.324c1.736,0,3.232-1.023,3.92-2.5l3.992,1.843
-		c-2.865,6.273-4.489,13.093-4.744,20.153l-5.154-0.167c-0.064-2.333-1.973-4.204-4.321-4.204c-2.388,0-4.324,1.936-4.324,4.324
-		c0,2.388,1.936,4.324,4.324,4.324c2.267,0,4.125-1.744,4.308-3.963l5.153,0.167c-0.013,0.496-0.021,0.993-0.021,1.491
-		c0,6.302,1.088,12.438,3.173,18.191l-4.231,1.558c-0.664-1.533-2.191-2.606-3.969-2.606c-2.388,0-4.324,1.936-4.324,4.324
-		c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-0.44-0.066-0.866-0.189-1.266l4.229-1.557
-		c2.409,6.464,6.084,12.436,10.898,17.611l-3.31,3.102c-0.776-0.741-1.827-1.197-2.985-1.197c-2.388,0-4.324,1.935-4.324,4.324
-		c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-1.057-0.38-2.025-1.01-2.776l3.311-3.102
-		c0.341,0.36,0.687,0.717,1.039,1.069c3.376,3.375,7.125,6.242,11.154,8.561l-20.601,37.972h-16.685v-25.743h-6.801v-48.882h2.645
-		v-1.063H564.32v1.063h2.645v24.652h-5.729l-5.467,28.096v-92.143h-2.399v-33.37h-12.075v-12.705h-6.46V220.37h-2.267v-18.294
-		h-0.586v18.294h-2.267v10.672h-6.46v12.705h-11.982v33.37h-2.491V337.7h-18.579v53.436h-61.639V287.814h4.954v-1.626h-4.954v-2.911
-		h-6.279v-4.781h-51.354v4.781h-6.279v2.911h-4.954v1.626h4.954v64.319h-8.4v-12.069h-51.819v14.737h-11.298v27.442h-18.294V292.55
-		h-6.098v-6.099h-4.828v-16.134h-1.017v16.134h-2.287v-20.2h-1.016v20.2h-2.811v6.099h-1.509v89.693h-37.859v-52.597h1.779v-3.557
-		h-11.688v-9.655h-5.59v9.655h-5.082v-9.655h-5.082v9.655h-9.885v-9.655h-30.261v9.655h-7.066v3.557h4.017v19.819h-11.18v44.72
-		h-15.346v-11.942h-17.084v26.044H84.29V419.4H53.82v31.849h891.682V419.4H918.278z M716.559,351.896l-7.135-13.152
-		c2.287-1.349,4.417-2.938,6.354-4.731l10.219,10.906C723.091,347.622,719.925,349.955,716.559,351.896z M689.85,309.7
-		c0.175,0.055,0.357,0.094,0.544,0.116l-1.082,33.274c-4.266-0.165-8.344-1.071-12.11-2.594L689.85,309.7z M676.758,340.314
-		c-1.218-0.512-2.402-1.089-3.548-1.726l15.875-29.261c0.102,0.07,0.209,0.133,0.32,0.19L676.758,340.314z M690.874,309.832
-		c0.203-0.01,0.401-0.041,0.591-0.091l11.067,31.4c-3.701,1.281-7.673,1.978-11.804,1.978c-0.313,0-0.625-0.004-0.936-0.012
-		L690.874,309.832z M691.917,309.581c0.159-0.072,0.311-0.157,0.453-0.254l15.875,29.261c-1.677,0.932-3.435,1.734-5.261,2.394
-		L691.917,309.581z M694.589,311.399l20.697,22.088c-1.893,1.751-3.973,3.303-6.206,4.623L694.589,311.399z M693.683,309.731
-		l-0.598-1.103c0.062-0.086,0.119-0.176,0.172-0.268l30.224,13.952c-1.93,4.091-4.602,7.766-7.844,10.847L693.683,309.731z
-		 M693.46,307.925c0.077-0.21,0.129-0.432,0.156-0.662l33.274,1.082c-0.186,4.809-1.313,9.38-3.204,13.534L693.46,307.925z
-		 M693.631,306.783c-0.011-0.217-0.046-0.428-0.102-0.63l31.244-11.503c1.388,3.836,2.146,7.971,2.146,12.279
-		c0,0.313-0.004,0.624-0.012,0.936L693.631,306.783z M693.364,305.702c-0.097-0.207-0.217-0.401-0.358-0.579l24.281-22.752
-		c3.15,3.404,5.654,7.411,7.319,11.828L693.364,305.702z M692.678,304.772c-0.188-0.17-0.399-0.315-0.627-0.433l12.647-30.797
-		c4.661,1.958,8.83,4.864,12.261,8.477L692.678,304.772z M691.606,304.157c-0.175-0.055-0.357-0.094-0.544-0.116l1.082-33.273
-		c4.265,0.164,8.344,1.071,12.11,2.594L691.606,304.157z M690.582,304.025c-0.203,0.01-0.401,0.041-0.591,0.09l-11.067-31.4
-		c3.701-1.281,7.672-1.978,11.804-1.978c0.313,0,0.625,0.004,0.936,0.012L690.582,304.025z M689.539,304.276
-		c-0.221,0.099-0.428,0.226-0.616,0.375L666.17,280.37c3.525-3.261,7.697-5.832,12.301-7.494L689.539,304.276z M688.572,304.978
-		c-0.143,0.158-0.268,0.332-0.373,0.518l-30.224-13.953c1.929-4.091,4.602-7.766,7.845-10.847L688.572,304.978z M687.996,305.932
-		c-0.077,0.211-0.129,0.432-0.156,0.662l-33.274-1.082c0.186-4.809,1.313-9.38,3.204-13.534L687.996,305.932z M687.825,307.075
-		c0.011,0.217,0.046,0.427,0.102,0.629l-31.244,11.503c-1.388-3.836-2.146-7.97-2.146-12.279c0-0.313,0.004-0.625,0.012-0.936
-		L687.825,307.075z M688.092,308.155c0.078,0.168,0.171,0.326,0.279,0.474l-0.198,0.365l-24.004,22.492
-		c-3.15-3.404-5.654-7.411-7.319-11.828L688.092,308.155z M687.446,310.332l-15.07,27.777c-2.912-1.72-5.564-3.835-7.88-6.272
-		L687.446,310.332z M672.866,339.221c1.169,0.649,2.376,1.238,3.618,1.759l-5.681,13.833c-1.732-0.721-3.424-1.537-5.07-2.445
-		L672.866,339.221z M676.929,341.163c3.843,1.555,8.006,2.479,12.36,2.647l-0.485,14.92c-6.107-0.221-12.028-1.496-17.555-3.735
-		L676.929,341.163z M689.769,343.828c0.319,0.008,0.638,0.013,0.959,0.013c4.215,0,8.267-0.712,12.043-2.02l4.97,14.101
-		c-5.399,1.87-11.131,2.844-17.013,2.844c-0.482,0-0.964-0.007-1.444-0.021L689.769,343.828z M703.225,341.661
-		c1.862-0.672,3.655-1.49,5.365-2.44l7.133,13.148c-2.417,1.333-4.933,2.468-7.528,3.394L703.225,341.661z M727.382,343.582
-		c-0.341,0.341-0.686,0.676-1.035,1.007l-10.217-10.904c3.31-3.144,6.038-6.895,8.007-11.07l13.579,6.269
-		C735.191,334.277,731.718,339.247,727.382,343.582z M737.917,328.448l-13.578-6.268c1.931-4.239,3.081-8.904,3.27-13.813
-		l14.921,0.485C742.281,315.718,740.702,322.349,737.917,328.448z M742.565,306.929c0,0.482-0.007,0.963-0.02,1.444l-14.917-0.485
-		c0.008-0.319,0.012-0.639,0.012-0.959c0-4.397-0.774-8.615-2.19-12.528l14.03-5.165
-		C741.507,294.832,742.565,300.799,742.565,306.929z M728.718,271.66c4.68,5.032,8.253,10.839,10.596,17.124l-14.032,5.167
-		c-1.699-4.508-4.255-8.598-7.47-12.072L728.718,271.66z M727.382,270.274c0.341,0.341,0.676,0.686,1.007,1.035l-10.904,10.217
-		c-3.502-3.687-7.756-6.653-12.513-8.65l5.681-13.833C716.831,261.615,722.507,265.399,727.382,270.274z M692.652,255.126
-		c6.107,0.221,12.028,1.496,17.555,3.735l-5.681,13.833c-3.843-1.555-8.006-2.479-12.36-2.647L692.652,255.126z M690.728,255.092
-		c0.482,0,0.964,0.007,1.444,0.02l-0.485,14.917c-0.319-0.008-0.638-0.012-0.959-0.012c-4.215,0-8.267,0.712-12.043,2.019
-		l-4.97-14.101C679.114,256.065,684.846,255.092,690.728,255.092z M673.261,258.094l4.97,14.102
-		c-4.698,1.696-8.956,4.319-12.553,7.648l-10.219-10.906C660.671,264.091,666.716,260.43,673.261,258.094z M654.074,270.274
-		c0.341-0.341,0.687-0.676,1.035-1.007l10.218,10.904c-3.31,3.144-6.038,6.895-8.007,11.071l-13.579-6.269
-		C646.265,279.58,649.738,274.61,654.074,270.274z M643.539,285.409l13.578,6.268c-1.931,4.239-3.081,8.905-3.27,13.813
-		l-14.921-0.485C639.175,298.14,640.754,291.509,643.539,285.409z M638.891,306.929c0-0.482,0.007-0.964,0.02-1.444l14.917,0.485
-		c-0.008,0.318-0.012,0.638-0.012,0.959c0,4.396,0.774,8.614,2.19,12.528l-14.03,5.166
-		C639.949,319.025,638.891,313.058,638.891,306.929z M652.738,342.197c-4.68-5.032-8.253-10.839-10.597-17.124l14.032-5.167
-		c1.699,4.508,4.255,8.598,7.47,12.072L652.738,342.197z M654.074,343.582c-0.341-0.341-0.676-0.686-1.007-1.035l10.904-10.217
-		c2.368,2.494,5.082,4.656,8.062,6.414l-7.135,13.152C660.988,349.642,657.35,346.859,654.074,343.582z M665.046,353.636
-		c1.692,0.934,3.431,1.771,5.21,2.512l-1.821,4.434c-0.413-0.131-0.853-0.202-1.309-0.202c-2.388,0-4.324,1.936-4.324,4.324
-		c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-1.762-1.054-3.276-2.566-3.95l1.816-4.423
-		c5.685,2.304,11.775,3.615,18.057,3.842l-0.148,4.534c-2.341,0.053-4.224,1.967-4.224,4.321c0,2.388,1.936,4.324,4.324,4.324
-		c2.388,0,4.324-1.936,4.324-4.324c0-2.26-1.734-4.113-3.944-4.306l0.148-4.535c0.496,0.014,0.993,0.021,1.491,0.021
-		c6.048,0,11.942-1.001,17.493-2.925l1.554,4.408c-1.471,0.69-2.491,2.184-2.491,3.916c0,2.388,1.936,4.324,4.324,4.324
-		c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324c-0.485,0-0.951,0.081-1.387,0.229l-1.547-4.388
-		c2.667-0.952,5.252-2.117,7.736-3.487l20.345,37.5h-92.055L665.046,353.636z"/>
-	<g>
-		
-			<linearGradient id="SVGID_00000121273610027325662480000007068999652675512506_" gradientUnits="userSpaceOnUse" x1="815.83" y1="285.1626" x2="815.83" y2="287.5796">
-			<stop  offset="0" style="stop-color:#403E40"/>
-			<stop  offset="1" style="stop-color:#161F21"/>
-		</linearGradient>
-		<path style="fill:url(#SVGID_00000121273610027325662480000007068999652675512506_);" d="M816.844,286.371
-			c0-0.667-0.454-1.208-1.014-1.208c-0.56,0-1.014,0.541-1.014,1.208c0,0.668,0.454,1.208,1.014,1.208
-			C816.39,287.58,816.844,287.039,816.844,286.371z"/>
-		
-			<linearGradient id="SVGID_00000011738580747612097720000010840228285618223286_" gradientUnits="userSpaceOnUse" x1="500" y1="287.5796" x2="500" y2="451.2495">
-			<stop  offset="0" style="stop-color:#403E40"/>
-			<stop  offset="1" style="stop-color:#161F21"/>
-		</linearGradient>
-		<polygon style="fill:url(#SVGID_00000011738580747612097720000010840228285618223286_);" points="927.404,433.241 921.11,391.136 
-			908.236,391.136 908.236,356.197 909.828,356.197 909.828,353.036 903.578,353.036 903.578,339.427 902.815,339.427 
-			902.815,353.036 898.496,353.036 898.496,341.887 897.734,341.887 897.734,353.036 871.695,353.036 871.695,356.197 
-			873.474,356.197 873.474,427.088 843.745,427.088 843.745,395.334 826.815,395.334 826.815,317.303 828.363,317.303 
-			828.363,313.475 824.982,313.475 824.982,308.574 821.091,308.574 821.091,306.732 821.091,301.129 821.091,296.267 
-			816.395,296.267 816.395,287.58 815.83,287.58 815.265,287.58 815.265,296.267 812.734,296.267 811.204,301.129 800.958,301.129 
-			800.958,308.574 774.141,308.574 774.141,313.475 770.76,313.475 770.76,317.303 772.309,317.303 772.309,368.073 
-			749.871,368.073 749.871,417.957 724.973,406.925 724.973,358.507 728.991,358.507 728.991,354.95 721.924,354.95 
-			721.924,345.294 691.664,345.294 691.664,354.95 681.778,354.95 681.778,345.294 676.696,345.294 676.696,354.95 671.615,354.95 
-			671.615,345.294 666.025,345.294 666.025,354.95 654.337,354.95 654.337,358.507 656.115,358.507 656.115,425.617 
-			644.765,425.617 644.765,424.913 642.711,424.913 642.711,405.789 644.765,405.789 644.765,404.255 642.711,404.255 
-			642.711,385.13 644.765,385.13 644.765,383.597 642.711,383.597 642.711,364.472 644.765,364.472 644.765,362.939 
-			642.711,362.939 642.711,343.814 644.765,343.814 644.765,342.28 642.711,342.28 642.711,323.156 644.765,323.156 
-			644.765,321.622 642.711,321.622 642.711,301.83 646.231,301.83 646.231,300.291 648.021,300.291 648.021,296.095 
-			614.595,296.095 614.595,291.429 615.682,291.429 615.682,290.081 597.484,290.081 597.484,291.429 598.571,291.429 
-			598.571,296.095 590.287,296.095 590.287,300.291 592.078,300.291 592.078,301.83 595.598,301.83 595.598,321.622 
-			593.543,321.622 593.543,323.156 595.598,323.156 595.598,342.28 593.543,342.28 593.543,343.814 595.598,343.814 
-			595.598,362.939 593.543,362.939 593.543,364.472 595.598,364.472 595.598,383.597 593.543,383.597 593.543,385.13 
-			595.598,385.13 595.598,404.255 593.543,404.255 593.543,405.789 595.598,405.789 595.598,424.913 593.543,424.913 
-			593.543,426.447 595.598,426.447 595.598,442.075 584.189,442.075 584.189,381.685 538.283,381.685 538.283,425.617 
-			530.83,425.617 530.83,288.763 525.315,288.763 525.315,292.286 515.14,294.775 515.14,292.487 509.625,292.487 509.625,296.124 
-			499.45,298.612 499.45,295.989 493.936,295.989 493.936,299.961 483.76,302.45 483.76,300.286 478.246,300.286 478.246,303.799 
-			468.071,306.288 468.071,304.423 462.557,304.423 462.557,438.816 454.799,438.816 454.799,367.168 426.065,367.168 
-			426.065,411.227 396.608,411.227 396.608,373.655 392.979,373.655 392.979,361.316 395.133,361.316 395.133,360.077 
-			385.601,360.077 385.601,356.197 384.584,356.197 384.584,360.077 381.535,360.077 381.535,340.162 380.773,340.162 
-			380.773,360.077 376.802,360.077 376.802,361.316 379.138,361.316 379.138,373.655 359.697,373.655 359.697,402.316 
-			340.771,402.316 330.886,438.816 311.053,438.816 311.053,319.642 284.794,319.642 284.794,315.373 286.286,315.373 
-			286.286,313.875 266.397,313.875 266.397,315.373 267.961,315.373 267.961,319.642 267.961,326.508 267.961,408.127 
-			255.579,408.127 255.579,377.289 259.98,377.289 259.98,374.497 228.825,374.497 228.825,355.867 222.882,355.867 
-			222.882,352.039 209.616,352.039 209.616,355.867 198.821,355.867 198.821,422.389 163.408,422.389 163.408,373.052 
-			133.589,373.052 133.589,412.021 107.712,412.021 107.712,436.954 89.054,436.954 89.054,405.609 64.517,405.609 64.517,432.333 
-			42.301,432.333 42.301,451.25 64.517,451.25 72.025,451.25 84.29,451.25 89.054,451.25 107.712,451.25 133.589,451.25 
-			142.285,451.25 146.941,451.25 163.408,451.25 198.821,451.25 209.616,451.25 222.882,451.25 228.825,451.25 252.067,451.25 
-			255.579,451.25 267.961,451.25 288.725,451.25 298.954,451.25 311.053,451.25 359.697,451.25 370.931,451.25 389.895,451.25 
-			396.608,451.25 426.568,451.25 434.618,451.25 462.557,451.25 465.314,451.25 468.071,451.25 478.246,451.25 483.76,451.25 
-			493.936,451.25 498.545,451.25 499.45,451.25 509.625,451.25 515.14,451.25 523.887,451.25 525.315,451.25 528.072,451.25 
-			530.83,451.25 538.283,451.25 576.227,451.25 581.647,451.25 584.189,451.25 595.598,451.25 615.682,451.25 634.069,451.25 
-			642.711,451.25 656.115,451.25 689.405,451.25 724.606,451.25 724.973,451.25 749.871,451.25 763.792,451.25 772.309,451.25 
-			777.689,451.25 819.353,451.25 826.815,451.25 835.736,451.25 843.745,451.25 873.474,451.25 895.58,451.25 900.105,451.25 
-			908.236,451.25 957.698,451.25 957.698,433.241 		"/>
-	</g>
-</g>
-</svg>
diff --git a/frontend/assets/cld-server.svg b/frontend/assets/cld-server.svg
new file mode 100644
index 0000000..b484198
--- /dev/null
+++ b/frontend/assets/cld-server.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>cld-server</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="SLICES-64px" transform="translate(-810.000000, -200.000000)">
+
+</g>
+        <g id="ICONS" transform="translate(-805.000000, -195.000000)">
+            <g id="cld-server" transform="translate(810.000000, 204.000000)">
+                <path d="M48,12 C51.313,12 54,9.313 54,6 C54,2.687 51.313,0 48,0 L6,0 C2.687,0 0,2.687 0,6 C0,9.313 2.687,12 6,12 L48,12 Z" id="Fill-424" fill="#969CE3">
+
+</path>
+                <path d="M10,6 C10,7.104 9.104,8 8,8 C6.896,8 6,7.104 6,6 C6,4.896 6.896,4 8,4 C9.104,4 10,4.896 10,6" id="Fill-425" fill="#7BBDEC">
+
+</path>
+                <path d="M48,30 C51.313,30 54,27.313 54,24 C54,20.687 51.313,18 48,18 L6,18 C2.687,18 0,20.687 0,24 C0,27.313 2.687,30 6,30 L48,30 Z" id="Fill-426" fill="#969CE3">
+
+</path>
+                <path d="M10,24 C10,25.104 9.104,26 8,26 C6.896,26 6,25.104 6,24 C6,22.896 6.896,22 8,22 C9.104,22 10,22.896 10,24" id="Fill-427" fill="#7BBDEC">
+
+</path>
+                <path d="M48,48 C51.313,48 54,45.313 54,42 C54,38.687 51.313,36 48,36 L6,36 C2.687,36 0,38.687 0,42 C0,45.313 2.687,48 6,48 L48,48 Z" id="Fill-428" fill="#969CE3">
+
+</path>
+                <path d="M10,42 C10,43.104 9.104,44 8,44 C6.896,44 6,43.104 6,42 C6,40.896 6.896,40 8,40 C9.104,40 10,40.896 10,42" id="Fill-429" fill="#7BBDEC">
+
+</path>
+                <path d="M48,12 C51.313,12 54,9.313 54,6 C54,2.687 51.313,0 48,0 L6,0 C2.687,0 0,2.687 0,6 C0,9.313 2.687,12 6,12 L48,12 Z" id="Stroke-430" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M10,6 C10,7.104 9.104,8 8,8 C6.896,8 6,7.104 6,6 C6,4.896 6.896,4 8,4 C9.104,4 10,4.896 10,6 Z" id="Stroke-431" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M48,6 L36,6" id="Stroke-432" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M48,30 C51.313,30 54,27.313 54,24 C54,20.687 51.313,18 48,18 L6,18 C2.687,18 0,20.687 0,24 C0,27.313 2.687,30 6,30 L48,30 Z" id="Stroke-433" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M10,24 C10,25.104 9.104,26 8,26 C6.896,26 6,25.104 6,24 C6,22.896 6.896,22 8,22 C9.104,22 10,22.896 10,24 Z" id="Stroke-434" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M48,24 L36,24" id="Stroke-435" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M48,48 C51.313,48 54,45.313 54,42 C54,38.687 51.313,36 48,36 L6,36 C2.687,36 0,38.687 0,42 C0,45.313 2.687,48 6,48 L48,48 Z" id="Stroke-436" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M10,42 C10,43.104 9.104,44 8,44 C6.896,44 6,43.104 6,42 C6,40.896 6.896,40 8,40 C9.104,40 10,40.896 10,42 Z" id="Stroke-437" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M48,42 L36,42" id="Stroke-438" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/frontend/assets/con-drill.svg b/frontend/assets/con-drill.svg
new file mode 100644
index 0000000..b095d26
--- /dev/null
+++ b/frontend/assets/con-drill.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>con-drill</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="SLICES-64px" transform="translate(-450.000000, -300.000000)">
+
+</g>
+        <g id="ICONS" transform="translate(-445.000000, -295.000000)">
+            <g id="con-drill" transform="translate(452.000000, 306.000000)">
+                <path d="M4,46 L20,46 C21.104,46 22,45.104 22,44 L22,36 C22,34.896 21.104,34 20,34 L13.375,34 L2,34 L2,44 C2,45.104 2.896,46 4,46" id="Fill-680" fill="#99A5B7">
+
+</path>
+                <path d="M40,4 L34,4 L34,12 L40,12 C41.104,12 42,11.104 42,10 L42,6 C42,4.896 41.104,4 40,4" id="Fill-681" fill="#E9EFFA">
+
+</path>
+                <path d="M30,16 C32.209,16 34,14.209 34,12 L34,4 C34,1.791 32.209,0 30,0 L4,0 C1.791,0 0,1.791 0,4 L0,12 C0,14.209 1.791,16 4,16 L30,16 Z" id="Fill-682" fill="#D3D873">
+
+</path>
+                <path d="M12.71,22 L18,22 C16.354,20.354 17.87,17.918 19,16 L14,16 L12.71,22 Z" id="Fill-683" fill="#F16963">
+
+</path>
+                <path d="M13.375,34 C11.926,34 10.75,32.824 10.75,31.375 C10.75,31.12 10.786,30.874 10.854,30.641 L14,16 L6,16 L2,34 L13.375,34 Z" id="Fill-684" fill="#AEC14A">
+
+</path>
+                <path d="M12.71,22 L18,22 C16.354,20.354 17.87,17.918 19,16" id="Stroke-685" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M42,8 L54,8" id="Stroke-686" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M34,4 L40,4 C41.104,4 42,4.896 42,6 L42,10 C42,11.104 41.104,12 40,12 L34,12" id="Stroke-687" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M2,34 L6,16" id="Stroke-688" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M6,8 L14,8" id="Stroke-689" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M6,4 L14,4" id="Stroke-690" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M2,34 L2,44 C2,45.104 2.896,46 4,46 L20,46 C21.104,46 22,45.104 22,44 L22,36 C22,34.896 21.104,34 20,34 L13.375,34" id="Stroke-691" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M13.375,34 C11.926,34 10.75,32.824 10.75,31.375 C10.75,31.12 10.786,30.874 10.854,30.641 L14,16" id="Stroke-692" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M2,34 L14,34" id="Stroke-693" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M30,16 C32.209,16 34,14.209 34,12 L34,4 C34,1.791 32.209,0 30,0 L4,0 C1.791,0 0,1.791 0,4 L0,12 C0,14.209 1.791,16 4,16 L30,16 Z" id="Stroke-694" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/frontend/assets/con-warning.svg b/frontend/assets/con-warning.svg
new file mode 100644
index 0000000..1e085b4
--- /dev/null
+++ b/frontend/assets/con-warning.svg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>con-warning</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="SLICES-64px" transform="translate(-720.000000, -300.000000)">
+
+</g>
+        <g id="ICONS" transform="translate(-715.000000, -295.000000)">
+            <g id="con-warning" transform="translate(718.000000, 302.000000)">
+                <path d="M50,46 C53.313,46 56,43.313 56,40 C56,38.751 55.358,37.299 55.358,37.299 L32.878,2.51 L32.88,2.509 C31.791,0.99 30.011,1.13686838e-13 28,1.13686838e-13 C25.989,1.13686838e-13 24.209,0.99 23.12,2.509 L23.122,2.51 L0.642,37.299 C0.642,37.299 0,38.751 0,40 C0,43.313 2.687,46 6,46 L50,46 Z" id="Fill-390" fill="#F3E777">
+
+</path>
+                <path d="M26,36 C26,34.896 26.896,34 28,34 C29.104,34 30,34.896 30,36 C30,37.104 29.104,38 28,38 C26.896,38 26,37.104 26,36" id="Fill-391" fill="#F16963">
+
+</path>
+                <path d="M32,16 C32,13.791 30.209,12 28,12 C25.791,12 24,13.791 24,16 L26,28 C26,29.104 26.896,30 28,30 C29.104,30 30,29.104 30,28 L32,16 Z" id="Fill-392" fill="#F16963">
+
+</path>
+                <path d="M26,36 C26,34.896 26.896,34 28,34 C29.104,34 30,34.896 30,36 C30,37.104 29.104,38 28,38 C26.896,38 26,37.104 26,36 Z" id="Stroke-393" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M32,16 C32,13.791 30.209,12 28,12 C25.791,12 24,13.791 24,16 L26,28 C26,29.104 26.896,30 28,30 C29.104,30 30,29.104 30,28 L32,16 Z" id="Stroke-394" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M50,46 C53.313,46 56,43.313 56,40 C56,38.751 55.358,37.299 55.358,37.299 L32.878,2.51 L32.88,2.509 C31.791,0.99 30.011,1.13686838e-13 28,1.13686838e-13 C25.989,1.13686838e-13 24.209,0.99 23.12,2.509 L23.122,2.51 L0.642,37.299 C0.642,37.299 0,38.751 0,40 C0,43.313 2.687,46 6,46 L50,46 Z" id="Stroke-395" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/frontend/assets/confused.svg b/frontend/assets/confused.svg
deleted file mode 100644
index e5182a2..0000000
--- a/frontend/assets/confused.svg
+++ /dev/null
@@ -1,427 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   version="1.1"
-   id="svg2"
-   width="2666.6667"
-   height="2666.6667"
-   viewBox="0 0 2666.6667 2666.6667"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg">
-  <defs
-     id="defs6" />
-  <sodipodi:namedview
-     id="namedview4"
-     pagecolor="#ffffff"
-     bordercolor="#000000"
-     borderopacity="0.25"
-     inkscape:showpageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="0"
-     inkscape:deskcolor="#d1d1d1" />
-  <g
-     id="g8"
-     inkscape:groupmode="layer"
-     inkscape:label="ink_ext_XXXXXX"
-     transform="matrix(1.3333333,0,0,-1.3333333,0,2666.6667)">
-    <g
-       id="g10"
-       transform="scale(0.1)">
-      <path
-         d="M 20000,0 H 0 V 20000 H 20000 V 0"
-         style="fill:#ffffff;fill-opacity:0;fill-rule:nonzero;stroke:none"
-         id="path12" />
-      <path
-         d="m 4293.02,3453 c 0,0 -2076.85,6972.9 -582.28,8525.6 998.98,1037.8 2057.85,-1250 3321.68,-39.7 1125.17,1077.5 -443.52,3791.9 1433.86,4502 1973.32,746.4 3589.92,-5298 5245.62,-4462.3 2009.2,1014.1 4007.7,-1044.6 2280.6,-8539 L 4293.02,3453"
-         style="fill:#d4e8ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path14" />
-      <path
-         d="m 9553.91,18409.2 c -99.33,69.4 -202.81,116.9 -307.55,141.1 l 14.96,109 c 113.67,-26.3 225.73,-77.7 333.06,-152.7 z m -931.64,-0.1 -45.97,93.2 c 101.02,83.9 212.31,138.4 330.8,162.1 l 12.98,-109.4 c -106.66,-21.3 -206.86,-70.4 -297.81,-145.9 z m 1429.23,-569.5 c -74.47,121.2 -151.38,228.5 -228.54,319 l 57.2,82.1 c 80.57,-94.5 160.64,-206.3 238.04,-332.1 z m -1842.21,-84.6 -76.46,49 c 55.99,147.2 118.08,277.3 184.55,386.8 l 66.99,-68.4 c -62.8,-103.5 -121.71,-227.1 -175.08,-367.4 z m 2208.01,-656.6 c -56.1,137 -113.4,265.7 -170.3,382.4 l 72,59.1 c 58.1,-119 116.5,-250.1 173.6,-389.6 z m -2431.48,-172.3 -82.73,26.9 c 29.74,154.4 62.53,300 97.45,432.5 l 80.69,-35.8 c -34.15,-129.6 -66.25,-272.1 -95.41,-423.6 z M 10706,16294.7 c -45.8,143 -92,279.8 -137.3,406.6 l 77.4,46.5 c 45.7,-128.1 92.4,-266.3 138.6,-410.6 z m -2848.35,-239.6 -84.39,15.8 c 17.24,154.9 36.2,303.9 56.35,442.8 l 83.8,-20.5 c -19.92,-137.3 -38.68,-284.8 -55.76,-438.1 z m 3093.75,-590.5 c -41.2,149.2 -80.1,285.6 -118.7,417 l 79.6,39.5 c 38.9,-132.1 77.9,-269.2 119.4,-419.2 z m -3171.32,-293.7 -84.94,9.8 c 10.62,155.3 22.18,305.2 34.36,445.6 l 84.74,-12.4 c -12.1,-139.5 -23.6,-288.6 -34.16,-443 z m 7639.12,-186.6 c -105.6,57.8 -212.5,93.6 -317.7,106.3 l 7.9,110.2 c 113.9,-13.8 229.3,-52.4 343,-114.5 z m -930.4,-135.5 -48.9,90.6 c 104.9,95.2 210.8,165.7 314.9,209.6 l 26.3,-105.3 c -96,-40.4 -194.3,-106 -292.3,-194.9 z m -3313.9,-227.4 c -42.5,164.7 -77.4,298.9 -110.1,422.4 l 80.7,35.9 c 32.7,-123.8 67.7,-258.3 110.2,-423.2 z m 4785.2,-137.8 c -82.1,109.2 -167.1,205.5 -252.7,286.3 l 50.3,89.5 c 89.3,-84.5 178,-184.9 263.4,-298.5 z M 4315.17,14304.8 c -106.41,68.7 -211.07,112.6 -311.08,130.3 l 11.57,109.6 c 109.22,-19.4 222.77,-66.8 337.5,-140.8 z m 3415.28,-23.2 -85.12,6.6 c 7.38,160.8 14.71,306.9 22.41,446.5 l 85.06,-7.9 c -7.68,-139.2 -14.99,-284.8 -22.35,-445.2 z m 6277.45,-43.5 -66.3,69.7 c 80,128 155.8,238.2 231.7,336.8 l 60.3,-78.2 c -73.8,-95.9 -147.7,-203.2 -225.7,-328.3 z m -10612.54,-33.8 -51.72,88 c 101.83,100.8 207.82,173.4 315.01,216 l 24.95,-105.8 c -97.49,-38.7 -194.47,-105.4 -288.24,-198.2 z m 12974.54,-417.1 c -61.1,129.4 -125.2,251.7 -190.4,363.7 l 68,66.7 c 66.9,-114.8 132.5,-240.2 195.1,-372.6 z m -11518.1,-4.7 c -87.15,110.1 -172.85,207.3 -254.71,289.1 l 52.01,87.6 c 84.46,-84.3 172.68,-184.4 262.19,-297.4 z m 6541.7,-7.8 c -39.1,148.7 -77.5,297.5 -109.9,423.4 l 80.9,35 c 32.3,-125.7 70.7,-274.3 109.7,-422.6 z m -8435.94,-225 -71.88,59.5 c 67.01,136.2 136.11,259.1 205.36,365.5 l 65.14,-71.4 c -66.82,-102.6 -133.64,-221.6 -198.62,-353.6 z m 10651.54,-31.3 -71.2,61 c 71.3,139.9 135,260.9 194.8,369.9 l 69.5,-64.2 c -59.3,-107.9 -122.5,-227.9 -193.1,-366.7 z m -5915.29,-128.2 -85.16,5.6 c 5.74,147.8 11.45,295.6 17.53,446.1 l 85.16,-5.8 c -6.08,-150.4 -11.79,-298.2 -17.53,-445.9 z m -2387.36,-267.1 c -77.38,124.6 -149.4,235.5 -220.19,339 l 63.8,73.4 c 71.69,-104.8 144.56,-217.1 222.8,-343 z m 11373.15,-120.8 c -45.9,138.6 -94.4,273.1 -144.2,400 l 76,50.2 c 50.7,-129 100,-265.8 146.5,-406.5 z m -5050.3,-69 c -38.6,125.7 -78.5,262.8 -122,419.3 l 80.2,37.5 c 43.2,-155.3 82.8,-291.3 121.1,-415.8 z m 1605.8,-163.6 -71.3,60.8 c 60.6,119.5 123.2,246.2 186.6,374.1 l 71.7,-59.8 c -63.5,-128.3 -126.2,-255 -187,-375.1 z m -10593.96,0 -78.01,44.6 c 46.81,137.6 96.69,272.7 149.7,404.7 l 75.61,-51.1 c -52.16,-130 -101.23,-262.9 -147.3,-398.2 z m 5014.77,-272.4 -85.1,7.2 c 6.47,129.6 13.05,275.3 20.11,445.4 l 85.15,-6 c -7.08,-170.5 -13.67,-316.6 -20.16,-446.6 z m -1934.3,-82.2 c -78.02,138.3 -143.03,251.9 -204.62,357.4 l 67.98,66.8 c 61.87,-106 127.16,-220 205.46,-358.9 z M 16914,12171.8 c -34.4,143.3 -71,284.4 -109,419.4 l 80.1,37.9 c 38.4,-136.6 75.5,-279.4 110.3,-424.5 z m -4980.2,-49 c -55.2,110.5 -109.9,240.5 -167.2,397.6 l 77.1,47.4 c 55.7,-152.7 108.5,-278.5 161.7,-384.8 z m 887.6,-76.1 -62.7,75.1 c 64.7,90.8 134,202.9 211.9,342.6 l 69.1,-64.9 c -79.9,-143.3 -151.3,-258.7 -218.3,-352.8 z m -10416.99,-105.4 -81.55,32.3 c 33.89,143.8 71.06,286.7 110.49,424.9 l 79.97,-38.4 c -38.86,-136.2 -75.5,-277.1 -108.91,-418.8 z m 9965.49,-238.4 c -66.4,0 -131.5,25.7 -193.6,76.5 l 45.4,93.6 c 93.3,-76.4 185.1,-76.6 284.2,-15.6 l 36.6,-99.9 c -58.5,-36.2 -116.6,-54.6 -172.6,-54.6 z m -6243.04,-9.1 c -69.32,121.4 -141.21,249.8 -203.16,360.6 l 69.03,65 c 61.83,-110.6 133.57,-238.7 202.66,-359.8 z m 1467.13,-89.9 -84.57,14.1 c 13.1,132 24.84,276.7 35.88,442.1 l 84.96,-9.6 c -11.15,-166.9 -23.01,-313.1 -36.27,-446.6 z m 9495.11,-288.4 c -25.2,146.1 -52.4,291 -80.9,430.6 l 82.4,28.3 c 28.8,-141 56.3,-287.2 81.7,-434.7 z m -14848.75,-232.7 -83.72,21 c 22.09,147.7 47.09,294.9 74.3,437.7 l 82.78,-26.6 c -26.87,-140.9 -51.55,-286.3 -73.36,-432.1 z m 4317.3,-90.8 c -67.93,98.2 -140.53,211.1 -221.94,345.3 l 67.01,68.5 c 80.26,-132.4 151.69,-243.5 218.38,-339.9 z m 869.04,-269.1 -75.94,50.3 c 39.03,99.2 73.54,236.8 102.56,409 l 83.31,-23.6 c -31.01,-184.1 -66.98,-326.6 -109.93,-435.7 z m -295.86,-263.2 c -118.49,24.2 -204.19,94.2 -322.92,215 l 53.9,85.7 c 104.01,-105.5 179.13,-168.9 278.11,-190.7 z M 17216,10444 c -17.8,147.7 -37.3,294.8 -57.9,437.2 l 83.8,20.5 c 20.8,-143.6 40.4,-291.8 58.3,-440.6 z m -15074.12,-237.3 -84.85,11 c 11.58,149.6 25.7,299.2 41.97,444.5 l 84.39,-15.9 c -16.09,-143.7 -30.06,-291.6 -41.51,-439.6 z M 17302,9563.6 c -11.4,148.5 -24.3,296.9 -38.3,441.1 l 84.6,13.8 c 14.1,-145 27.1,-294.4 38.6,-444 z m -15200.65,-241.4 -85.25,2.2 c 2.37,150.2 6.95,300.6 13.61,447.1 l 85.13,-6.5 c -6.6,-145.1 -11.14,-294.1 -13.49,-442.8 z M 17353,8678.1 c -5.9,148.6 -13.1,297.7 -21.4,443.2 l 85,8.2 c 8.4,-146.3 15.7,-296.3 21.6,-445.8 z m -15326.57,-248 c -5.66,149.8 -9.41,300.1 -11.15,446.9 l 85.26,1.8 c 1.73,-145.6 5.45,-294.8 11.06,-443.3 z m 15346.77,-640 c -1,148.8 -3.2,298.3 -6.5,444.2 l 85.2,3.2 c 3.4,-146.6 5.5,-296.8 6.6,-446.4 z M 2081.68,7538.7 c -12.72,148.9 -23.78,298.7 -32.89,445.1 l 84.99,8.9 c 9.05,-145.3 20.03,-294 32.65,-441.8 z m 15369.62,-640.4 -85.3,3.2 c 3.3,148.7 5.6,298.2 6.8,444.3 l 85.3,-1.2 c -1.2,-146.8 -3.5,-296.9 -6.8,-446.3 z M 2176.65,6653.2 c -18.96,147.5 -36.52,296.1 -52.18,441.9 l 84.46,15.3 c 15.55,-144.8 32.99,-292.5 51.83,-438.9 z m 15242.75,-646.6 -85.2,7 c 7.3,148 13.6,297.3 18.9,443.8 l 85.1,-5.2 c -5.2,-147 -11.6,-297 -18.8,-445.6 z M 2307.41,5775.7 c -24.63,145.6 -48.06,292.9 -69.65,437.7 l 83.72,21 c 21.46,-143.9 44.75,-290.3 69.22,-435 z m 15057.69,-658.8 -84.9,10.4 c 10.8,148.1 20.8,297.1 29.7,442.9 l 85,-8.8 c -9,-146.3 -19,-295.9 -29.8,-444.5 z M 2471.37,4907.6 c -29.85,143 -58.79,288.6 -86.04,432.8 l 82.82,26.3 c 27.09,-143.3 55.86,-288.1 85.52,-430.2 z m 14819.03,-677.8 -84.7,13.5 c 14.1,147.6 27.4,296.2 39.7,441.7 l 84.8,-12 c -12.3,-146.1 -25.7,-295.2 -39.8,-443.2 z m -14622.37,-179 c -34.86,138.6 -69.36,282.2 -102.52,426.8 l 81.73,31.6 c 32.95,-143.7 67.22,-286.4 101.86,-424.1 l -81.07,-34.3"
-         style="fill:#dce6ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path16" />
-      <path
-         d="m 17830.8,5733.6 c -707.7,136.1 -592.2,-1093.4 -1600.9,-1093.4 -922.2,0 -1217.2,4682 -1888.2,3343.6 -3440,-6861.3 -1442.5,2917.9 -4178.2,3042.1 C 8926.46,11082.1 8102.16,9370.8 7798.19,6340.9 7357.57,3601.7 6335.71,8430.1 5284.1,7981.2 4615.76,7695.8 4692.3,4640.2 3770.07,4640.2 2761.39,4640.2 2876.86,5869.7 2169.23,5733.6 1407.35,5587.1 1179.79,3411 1179.79,3411 H 18820.2 c 0,0 -227.5,2176.1 -989.4,2322.6"
-         style="fill:#eef7ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path18" />
-      <path
-         d="m 17204.1,4402.8 c -651,58.1 -544.8,-466.9 -1472.7,-466.9 -848.4,0 -825.1,1176.5 -1392.9,1426.6 C 13293,5823 12431,3492.4 12025.6,4662.1 c -769.9,3103.6 -3015.31,4660.1 -4051.21,0 -405.36,-1169.7 -1353.29,917.4 -2312.9,700.4 -590.67,-133.6 -544.45,-1426.6 -1392.88,-1426.6 -927.96,0 -821.72,525 -1472.73,466.9 C 2094.97,4340.2 1885.62,3411 1885.62,3411 H 18114.4 c 0,0 -209.4,929.2 -910.3,991.8"
-         style="fill:#dce6ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path20" />
-      <path
-         d="m 1192.91,3411 c 0,0 -123.77,-481.6 388.96,-602.2 701.3,-164.9 4817.85,-598.2 3817.79,-927.5 -564.53,-185.9 288.19,-438.3 3037.88,-531.2 2749.66,-92.9 7467.96,271.2 5881.26,810 -1586.7,538.8 4877.9,130.1 4484.1,1250.9 H 1192.91"
-         style="fill:#cfddf9;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path22" />
-      <path
-         d="m 16471.4,10722.6 -57.7,0.6 c 0,0.7 0.5,72.8 -15.1,187.5 l 57.2,7.8 c 16.2,-119.3 15.7,-192.8 15.6,-195.9"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path24" />
-      <path
-         d="m 14594.9,12666.8 c -122.7,21 -252.8,35.7 -386.6,43.9 l 3.5,57.6 c 135.9,-8.3 268.1,-23.3 392.8,-44.6 z m 737.1,-234.4 c -111.6,56.3 -232.5,104.9 -359.3,144.5 l 17.2,55.2 c 129.9,-40.6 253.7,-90.5 368,-148.2 z m 606.7,-471.6 c -83.2,97.4 -177.2,187 -279.5,266.1 l 35.3,45.7 c 105.4,-81.6 202.4,-173.9 288.1,-274.3 z m 373,-672.9 c -40.7,124.3 -92.4,243.8 -153.7,355 l 50.6,27.9 c 63.1,-114.4 116.2,-237.2 158,-365 l -54.9,-17.9"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path26" />
-      <path
-         d="m 13625.5,12708.3 -3.6,57.7 c 65.1,4 130.2,6.9 193.4,8.6 l 1.5,-57.7 c -62.5,-1.7 -126.9,-4.5 -191.3,-8.6"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path28" />
-      <path
-         d="m 3312.12,10409.2 c -108.34,52 -169.59,93.3 -172.14,95 l 32.39,47.8 c 0.6,-0.4 60.63,-40.8 164.73,-90.7 l -24.98,-52.1"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path30" />
-      <path
-         d="m 5143.75,10461 -28.79,50.1 c 103.71,59.6 206.21,130.8 304.66,211.5 l 36.61,-44.7 c -100.89,-82.7 -206.03,-155.7 -312.48,-216.9 z m -718.36,-243.7 -7.08,57.3 c 121.76,15 242.89,42.9 360.02,83 l 18.7,-54.6 c -120.9,-41.4 -245.94,-70.2 -371.64,-85.7 z m -381.28,-7.7 c -124.69,10 -250.91,32.4 -375.16,66.5 l 15.28,55.7 c 120.78,-33.1 243.42,-54.9 364.52,-64.7 l -4.64,-57.5"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path32" />
-      <path
-         d="m 5732.86,10939.1 -42.29,39.3 c 42.32,45.5 84.62,93.8 125.72,143.5 l 44.5,-36.8 c -41.81,-50.6 -84.85,-99.7 -127.93,-146"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path34" />
-      <path
-         d="m 3183.2,14357.8 -54.04,20.3 c 1.05,2.8 26.51,70.1 80.03,178.2 l 51.75,-25.7 c -52.11,-105.2 -77.49,-172.2 -77.74,-172.8"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path36" />
-      <path
-         d="m 5531.51,16016.1 c -94.63,15.3 -195.39,18.7 -299.61,10.2 -18.98,-1.5 -38.14,-3.4 -56.95,-5.4 l -6.22,57.4 c 19.32,2.1 38.99,4 58.48,5.6 108.85,8.8 214.29,5.2 313.5,-10.8 z m -1046.07,-194.5 -25.39,51.9 c 111.4,54.5 227.61,99.4 345.4,133.5 l 16.02,-55.5 c -114.57,-33.1 -227.63,-76.8 -336.03,-129.9 z m 1660.61,-137.9 c -84.88,89.9 -179,163.4 -279.73,218.4 l 27.68,50.7 c 106.06,-58 204.98,-135.2 294.04,-229.4 z m -2248.72,-277.5 -39.88,41.8 c 90.9,86.8 186.71,166.1 284.77,235.8 l 33.45,-47 c -95.79,-68.1 -189.44,-145.7 -278.34,-230.6 z m 2611.64,-338.7 c -43.71,118.7 -94.58,228.8 -151.22,327.4 l 50.07,28.7 c 58.25,-101.3 110.51,-214.4 155.34,-336.2 z m -3069.19,-221.6 -48.6,31.2 c 67.19,104.7 139.9,205.4 216.1,299.1 l 44.81,-36.4 c -74.84,-92.1 -146.27,-191 -212.31,-293.9 z m 3233.97,-483.3 c -15.02,122.7 -36,243 -62.33,357.6 l 56.27,12.9 c 26.79,-116.5 48.12,-238.8 63.38,-363.5 z m 76.48,-729.3 -57.59,4.3 c 6.24,84.5 9.41,172.2 9.41,260.8 -0.01,33.9 -0.47,68.1 -1.38,101.9 l 57.72,1.6 c 0.93,-34.3 1.39,-69.1 1.4,-103.5 0,-90 -3.22,-179.2 -9.56,-265.1"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path38" />
-      <path
-         d="m 6648.41,13076.9 -54.64,18.7 c 18.56,54.3 35.19,115.7 49.44,182.4 l 56.47,-12.1 c -14.72,-68.9 -31.97,-132.5 -51.27,-189"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path40" />
-      <path
-         d="m 6654.87,8152.8 c -116.31,30.5 -184.1,56.7 -186.93,57.8 l 20.92,53.9 c 0.66,-0.3 67.88,-26.2 180.68,-55.8 l -14.67,-55.9"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path42" />
-      <path
-         d="m 8620.13,8450.3 -34.16,46.5 c 105.3,77.3 204.97,167.4 296.24,267.7 l 42.73,-38.8 c -93.86,-103.2 -196.4,-195.9 -304.81,-275.4 z m -745.65,-335.5 -12.55,56.3 c 132.11,29.4 259.71,71.5 379.27,125 l 23.61,-52.7 C 8141.7,8188.3 8010.37,8145 7874.48,8114.8 Z m -511.31,-54.5 c -100.12,0 -202.91,5.9 -305.52,17.5 l 6.48,57.4 c 135.25,-15.3 270.04,-20.4 400.81,-15.1 l 2.37,-57.6 c -34.41,-1.5 -69.45,-2.2 -104.14,-2.2"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path44" />
-      <path
-         d="m 9173.35,9053 -48.74,30.9 c 33.35,52.5 65.77,107.8 96.36,164.3 l 50.78,-27.5 c -31.22,-57.7 -64.33,-114.1 -98.4,-167.7"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path46" />
-      <path
-         d="m 11261.6,9925 -11.8,56.5 c 3,0.6 74.5,15.4 194.9,23.7 l 4,-57.6 c -116.1,-8 -186.4,-22.5 -187.1,-22.6"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path48" />
-      <path
-         d="m 12165.2,9886.5 c -115.4,28.1 -235.2,47.6 -356,57.8 l 4.9,57.6 c 123.8,-10.5 246.5,-30.5 364.8,-59.3 z m 659.3,-283 c -100.1,65.2 -206.9,122.2 -317.5,169.5 l 22.7,53.1 c 113.6,-48.6 223.4,-107.2 326.3,-174.2 z m 527.2,-486.9 c -75.3,96 -157.3,185.3 -243.6,265.4 l 39.3,42.3 c 88.5,-82.1 172.6,-173.7 249.8,-272.1 l -45.5,-35.6"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path50" />
-      <path
-         d="m 13644.2,8649 c -28.6,57.6 -59,114.1 -90.2,167.9 l 49.9,28.9 c 31.9,-54.8 62.8,-112.4 92,-171.1 l -51.7,-25.7"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path52" />
-      <path
-         d="m 15679.2,14566.9 c -0.1,0.8 -15.4,71 -52,182.1 l 54.8,18.1 c 37.7,-114.4 53,-185.1 53.7,-188 l -56.5,-12.2"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path54" />
-      <path
-         d="m 14275.4,16296.7 c -129.2,50.1 -266.4,87.4 -407.9,110.9 l 9.4,57 c 145.4,-24.2 286.5,-62.6 419.4,-114.1 z m 702.5,-462.4 c -101.6,101.6 -211.7,191.9 -327.2,268.3 l 31.9,48.2 c 118.7,-78.6 231.8,-171.3 336.1,-275.7 z m 487.7,-692 c -64.3,129.8 -136.9,252.9 -216.1,366.2 l 47.3,33.1 c 80.8,-115.7 155,-241.3 220.5,-373.7 l -51.7,-25.6"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path56" />
-      <path
-         d="m 13253.9,16429.5 -4.7,57.6 c 65.4,5.3 130.8,8.4 194.2,9.3 l 0.7,-57.8 c -62.1,-0.8 -126.1,-3.8 -190.2,-9.1"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path58" />
-      <path
-         d="m 12982.4,16157.3 -36.6,44.6 c 92.8,76.2 154.4,115.5 157,117.2 l 30.9,-48.8 c -0.6,-0.4 -61.5,-39.3 -151.3,-113"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path60" />
-      <path
-         d="m 12467.4,15582.4 -48.6,31.2 c 69.6,108.5 150.6,214.4 240.8,314.7 l 43,-38.6 c -88.2,-98 -167.3,-201.4 -235.2,-307.3 z m -283.7,-712.8 -56.9,9.9 c 22.4,128.9 59.2,257.4 109.3,381.9 l 53.5,-21.6 c -48.5,-120.7 -84.2,-245.2 -105.9,-370.2 z m -25.3,-779.4 c -32.2,131.4 -51.4,263.6 -56.9,392.8 l 57.7,2.5 c 5.4,-125.5 24,-253.8 55.3,-381.6 z m 307.4,-727.2 c -70,117.3 -130.8,235.6 -180.6,351.8 l 53,22.8 c 48.9,-113.9 108.5,-229.9 177.1,-345 l -49.5,-29.6"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path62" />
-      <path
-         d="m 12806,12882.7 c -41.5,50.6 -81.7,101.9 -119.5,152.4 l 46.2,34.6 c 37.3,-49.8 77,-100.5 118,-150.5 l -44.7,-36.5"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path64" />
-      <path
-         d="m 9775.23,15692.4 c -99.69,63.6 -162.9,94.4 -163.53,94.7 l 25.13,52 c 2.67,-1.3 66.58,-32.4 169.46,-98 l -31.06,-48.7"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path66" />
-      <path
-         d="m 10396.6,15168.5 c -91.9,99.6 -190.9,194.4 -294.3,281.8 l 37.3,44.1 c 105.2,-88.9 205.9,-185.4 299.4,-286.7 z m 471.2,-662.1 c -63.5,119 -135.7,235.5 -214.4,346 l 47,33.5 c 80.2,-112.6 153.7,-231.1 218.3,-352.4 z m 286.8,-760.1 c -31.6,132.5 -71.6,263.5 -119,389.3 l 54,20.3 c 48.3,-128 89,-261.3 121.2,-396.2 z m 94.6,-808.1 c -0.8,137.7 -9,274.6 -24.2,406.9 l 57.4,6.6 c 15.5,-134.4 23.7,-273.4 24.5,-413.2 z m -16.7,-822.6 -56.8,10.2 c 24.6,136.4 43.3,272.5 55.5,404.7 l 57.5,-5.3 c -12.4,-133.8 -31.3,-271.6 -56.2,-409.6 z m -206.1,-799.4 -54.8,18.1 c 43.7,131.9 82.8,263.9 116.1,392.3 l 55.9,-14.5 c -33.7,-129.7 -73.1,-262.9 -117.2,-395.9"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path68" />
-      <path
-         d="m 10811.3,10749.1 -53.1,22.7 c 25.2,59.1 49.7,118.8 73,177.3 l 53.6,-21.3 c -23.4,-58.9 -48.1,-119 -73.5,-178.7"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path70" />
-      <path
-         d="m 6577.61,12430.8 c -29.23,119.4 -32.99,192 -33.13,195 l 57.67,2.8 -28.84,-1.4 28.84,1.4 c 0.04,-0.7 3.78,-70.7 31.55,-184 l -56.09,-13.8"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path72" />
-      <path
-         d="m 6900.24,11739.2 c -74.68,106 -139.66,217.3 -193.14,330.6 l 52.23,24.6 c 52.06,-110.3 115.35,-218.6 188.13,-322 z m 528.53,-549.5 c -102.23,80.1 -197.88,165.9 -284.28,255.2 l 41.49,40.1 c 84.57,-87.4 178.23,-171.4 278.37,-249.8 z m 650.21,-396.2 c -117.43,55.6 -230.45,116.1 -335.93,180 l 29.9,49.4 c 103.8,-62.9 215.07,-122.5 330.72,-177.2 l -24.69,-52.2"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path74" />
-      <path
-         d="m 8613.58,10582.6 c -61.96,20.2 -123.5,41.5 -182.91,63.5 l 20.03,54.2 c 58.7,-21.7 119.52,-42.9 180.76,-62.8 l -17.88,-54.9"
-         style="fill:#8a9edd;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path76" />
-      <path
-         d="m 9399.66,14352.4 c -25.82,-312.6 -491.29,-282.1 -476.12,31.1 25.82,312.6 491.29,282.1 476.12,-31.1"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path78" />
-      <path
-         d="m 8626.49,16483 c -56.13,589.3 492.42,1026.6 1057.4,858.1 740.11,-235.8 678.81,-1244.2 134.62,-1659.9 -255.48,-174.4 -525.96,-512 -569.44,-785.4 -31.42,-160.7 -160.33,-121.5 -179.62,31.3 -35.11,696.8 367.53,799.1 628.73,1288.5 291.64,817.7 -664.7,873.8 -954.3,246.8 -28.61,-52.9 -113.26,-42.1 -117.39,20.6"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path80" />
-      <path
-         d="m 6022.29,11075.1 c -41.44,-240.9 -400.72,-185.4 -367.5,56.8 41.44,240.9 400.72,185.3 367.5,-56.8"
-         style="fill:#fcb4b4;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path82" />
-      <path
-         d="m 5567.87,12782.2 c -3.25,461.3 452.54,763.2 879.64,593.8 558.45,-233.7 441.82,-1012.4 -9.09,-1297.9 -210.29,-118 -443.38,-361.5 -495.85,-570.8 -35.39,-122.6 -132.78,-83.4 -137.31,36.6 20.44,543.4 340.03,595.2 576.31,957.3 282.38,614.8 -456.24,723.8 -723.98,256.9 -25.83,-39.1 -90.81,-24.9 -89.72,24.1"
-         style="fill:#fcb4b4;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path84" />
-      <path
-         d="m 5868.06,6516.9 c -48.03,-279.3 -464.5,-214.9 -425.99,65.8 48.03,279.2 464.49,214.8 425.99,-65.8"
-         style="fill:#3a72aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path86" />
-      <path
-         d="m 5341.31,8495.6 c -3.77,534.8 524.58,884.8 1019.65,688.3 647.34,-270.9 512.15,-1173.5 -10.54,-1504.4 -243.75,-136.7 -513.94,-419.1 -574.77,-661.6 -41.02,-142.2 -153.92,-96.7 -159.16,42.3 23.69,630 394.15,690 668.03,1109.7 327.33,712.7 -528.86,839.1 -839.21,297.9 -29.94,-45.4 -105.26,-29 -104,27.8"
-         style="fill:#3a72aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path88" />
-      <path
-         d="m 13907.2,6164.4 c 3.8,-276.6 -407.4,-289.3 -420.7,-13.1 -3.9,276.7 407.4,289.4 420.7,13.1"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path90" />
-      <path
-         d="m 13047.4,7969.3 c -99.4,512.6 345.1,943.1 855.4,843.2 669.8,-144.1 701.6,-1034.7 259.2,-1445.8 -209.5,-174.9 -418.3,-494.3 -433.2,-737.9 -13.9,-143.8 -130.4,-120.4 -160.4,12.1 -90,608.9 254.8,732.8 442.6,1184.7 186.5,742.6 -657.8,710.6 -858.8,135.6 -20.6,-48.9 -95.9,-46.6 -104.8,8.1"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path92" />
-      <path
-         d="m 13116.6,15647.8 c -32.3,-187.8 -312.5,-144.5 -286.6,44.3 32.3,187.8 312.5,144.5 286.6,-44.3"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path94" />
-      <path
-         d="m 12762.3,16978.8 c -2.6,359.6 352.8,595.1 685.8,463 435.4,-182.3 344.5,-789.4 -7.1,-1012 -163.9,-91.9 -345.7,-281.9 -386.6,-445 -27.6,-95.6 -103.5,-65 -107,28.5 15.9,423.7 265.1,464.1 449.3,746.4 220.2,479.4 -355.7,564.4 -564.5,200.3 -20.1,-30.5 -70.8,-19.4 -69.9,18.8"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path96" />
-      <path
-         d="m 2750.72,12878.8 c -32.31,-187.8 -312.43,-144.5 -286.53,44.3 32.31,187.8 312.43,144.5 286.53,-44.3"
-         style="fill:#3a72aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path98" />
-      <path
-         d="m 2396.42,14209.8 c -2.54,359.6 352.84,595.1 685.84,462.9 435.41,-182.2 344.47,-789.3 -7.09,-1011.9 -163.96,-91.9 -345.69,-281.9 -386.6,-445 -27.6,-95.6 -103.53,-65 -107.06,28.5 15.93,423.7 265.11,464.1 449.33,746.4 220.17,479.4 -355.72,564.4 -564.47,200.3 -20.14,-30.5 -70.8,-19.4 -69.95,18.8"
-         style="fill:#3a72aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path100" />
-      <path
-         d="m 3281.35,9401.2 c 63.84,-165.3 -180.32,-264.4 -249.73,-101.4 -63.83,165.3 180.33,264.4 249.73,101.4"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path102" />
-      <path
-         d="m 2363.66,10294.1 c -173.63,285.7 -2.42,643.1 326.31,696.6 434.34,62.3 651.45,-465.5 477.14,-810.8 -86.93,-151.6 -141.32,-389.8 -96.13,-539.5 23.61,-89.4 -51.59,-101.3 -99.01,-28.3 -189.44,345.6 -9.9,496.7 2.39,809.9 -53.06,487.5 -553.08,280.5 -545.95,-109.5 -1.5,-34 -47.21,-49.3 -64.75,-18.4"
-         style="fill:#eb5648;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path104" />
-      <path
-         d="m 16509.2,13137 c 63.8,-165.3 -180.4,-264.4 -249.8,-101.4 -63.8,165.3 180.3,264.3 249.8,101.4"
-         style="fill:#fcb4b4;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path106" />
-      <path
-         d="m 15591.5,14029.8 c -173.7,285.8 -2.5,643.2 326.3,696.6 434.3,62.4 651.4,-465.4 477.1,-810.7 -86.9,-151.6 -141.3,-389.8 -96.1,-539.5 23.6,-89.5 -51.6,-101.3 -99,-28.3 -189.5,345.6 -9.9,496.7 2.4,809.9 -53.1,487.5 -553.1,280.5 -546,-109.5 -1.5,-34 -47.2,-49.3 -64.7,-18.5"
-         style="fill:#fcb4b4;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path108" />
-      <path
-         d="m 5574.3,15579.4 c 63.83,-165.2 -180.33,-264.3 -249.74,-101.3 -63.83,165.2 180.33,264.3 249.74,101.3"
-         style="fill:#9358e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path110" />
-      <path
-         d="m 4656.6,16472.3 c -173.62,285.8 -2.42,643.2 326.32,696.6 434.33,62.4 651.44,-465.4 477.13,-810.7 -86.93,-151.6 -141.31,-389.9 -96.12,-539.5 23.6,-89.5 -51.59,-101.3 -99.02,-28.4 -189.43,345.7 -9.9,496.8 2.39,809.9 -53.06,487.6 -553.08,280.6 -545.94,-109.5 -1.51,-33.9 -47.21,-49.3 -64.76,-18.4"
-         style="fill:#9358e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path112" />
-      <path
-         d="m 13548.2,10896.5 c 34,-242.1 -325.1,-298.7 -367.3,-58 -34,242.1 325.1,298.7 367.3,58"
-         style="fill:#9358e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path114" />
-      <path
-         d="m 12594.9,12383.7 c -143.7,438.4 198.3,864.9 656.7,833.7 603.1,-52.2 729.5,-829.4 387.1,-1238.8 -164.3,-176.4 -312,-479.5 -298.2,-694.8 3.7,-127.6 -101,-119.9 -141.9,-7 -146.3,523.8 142.3,670.5 256.9,1087.4 81.5,671.7 -655.2,550.3 -767.8,24 -12.7,-45.2 -78.9,-51.5 -92.8,-4.5"
-         style="fill:#9358e0;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path116" />
-      <path
-         d="m 15980.9,9054.5 c -41.9,-196.1 -334.5,-138.7 -299.3,58.6 41.9,196 334.5,138.7 299.3,-58.6"
-         style="fill:#3a72aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path118" />
-      <path
-         d="m 15664.8,10468.2 c 12.6,378.1 396,610.5 740.4,457.6 449.9,-209.9 328.6,-844.2 -50.2,-1063.2 -176.2,-89.7 -375.3,-281.6 -425.2,-451.4 -33,-99.3 -111.5,-63.9 -111.3,34.5 34.7,444.6 298.3,476.6 503.8,765.5 251.7,494.5 -350,608.1 -584.7,234.4 -22.5,-31.3 -75.3,-17.5 -72.8,22.6"
-         style="fill:#3a72aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path120" />
-      <path
-         d="m 9829.39,11430.5 c -4.09,30.7 -6.61,63.9 -7.94,98.5 -7.94,200.3 23.22,448.5 39.46,541.4 4.45,25.1 7.7,38.8 8.91,37.1 1.44,5.9 3.12,11.7 5.05,17.3 21.54,67.4 67.13,108.1 119.95,126.3 0.12,0 0.12,0 0.12,0 78.16,26.7 172.26,4.1 229.76,-55.1 1.2,-1.2 2.3,-2.5 3.4,-3.7 36.3,-39.2 56.8,-93.6 47,-159.8 -0.5,-3 -0.8,-6.2 -1.4,-9.2 -0.7,-4.2 -1.6,-8.3 -2.5,-12.4 -9.7,6.4 -36.6,-254.6 -36.9,-444 0,-62.4 2.9,-117.1 10.3,-151.9 388.6,-116.5 -780.14,-499.7 -415.21,15.5"
-         style="fill:#f99370;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path122" />
-      <path
-         d="m 9425.7,11232.7 c -278.35,-362.5 -406.1,-782.9 -689.45,-1125.7 -19.53,-17.2 151.98,849.6 231.51,1344.4 58.72,155.7 -101.41,204.4 -101.41,204.4 -546,-389.6 -1328.17,-1910.5 -272.03,-2235.4 776.2,-175.2 1131.79,843.2 1499.18,1332.3 297.8,435.3 -350.61,900.4 -667.8,480"
-         style="fill:#f99370;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path124" />
-      <path
-         d="m 7970.83,9905.5 c 6.84,-241.8 173.6,-599.3 638.29,-599.3 h 1.54 c 265.96,0.7 462.48,190 610.42,458.7 279.12,506.6 385.34,1296.1 457.34,1636.7 -311.62,-34.2 -736.3,-499.8 -867.99,-883.1 36.26,164.7 87.91,412.2 108.43,589.4 5.65,48.4 8.9,91.7 8.9,126.5 -32.33,-1.7 -217.21,-8.7 -346,155.5 -5.13,-6.3 -31.81,-36.4 -71.15,-87 -161.97,-207.7 -540.12,-758.4 -539.78,-1397.4"
-         style="fill:#1d3f70;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path126" />
-      <path
-         d="m 9534.24,12366.2 c 0,0 -20.82,215.2 29.29,370.9 l 129.58,-46.1 -158.87,-324.8"
-         style="fill:#8e4a35;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path128" />
-      <path
-         d="m 9602.41,11737.4 c 212.61,-164.9 633.59,-146.2 760.69,28.2 474.5,650.7 -456.88,1788 -764.69,757.4 -111.38,-296.9 -346.23,-466 4,-785.6"
-         style="fill:#f99370;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path130" />
-      <path
-         d="m 9833.61,12330.7 c -8.43,12.7 -4.94,29.9 7.8,38.3 12.73,8.4 29.89,4.9 38.32,-7.8 8.42,-12.8 4.93,-29.9 -7.8,-38.3 -12.74,-8.5 -29.9,-5 -38.32,7.8"
-         style="fill:#c16256;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path132" />
-      <path
-         d="m 9598.2,12342.9 c -8.43,12.8 -4.94,29.9 7.8,38.3 12.73,8.5 29.89,5 38.32,-7.8 8.43,-12.7 4.93,-29.8 -7.8,-38.3 -12.74,-8.4 -29.89,-4.9 -38.32,7.8"
-         style="fill:#c16256;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path134" />
-      <path
-         d="m 9697,12113.3 c 16.32,-0.1 32.62,2.6 45.99,8.7 5.27,2.4 7.62,8.6 5.22,13.8 -2.33,5.3 -8.63,7.6 -13.81,5.2 -33.63,-15.1 -84.94,-3.3 -93.49,11.7 -3.01,5.3 3.83,11.6 10.1,16 55.24,38.7 82.01,154.7 83.11,159.7 1.26,5.6 -2.27,11.2 -7.9,12.5 -5.48,1.1 -11.22,-2.3 -12.51,-7.9 -0.26,-1.2 -26.08,-113.1 -74.7,-147.1 -26.53,-18.6 -20.22,-36.7 -16.29,-43.6 10.27,-18 42.3,-28.9 74.28,-29"
-         style="fill:#c16256;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path136" />
-      <path
-         d="m 9624.27,12600.2 c 142.71,96.3 414.63,49.1 549.03,65.7 0,0 -2.3,-230.2 245,-365.7 43.2,-206.6 87.9,-293.8 -97.3,-572.8 v 0 c 15,11.8 29,24.5 42.1,38.2 h 0.3 c 585.7,740.1 -380.67,1756.7 -739.13,834.6"
-         style="fill:#e57d61;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path138" />
-      <path
-         d="m 9458.24,13034.2 c 66.26,178.5 309.4,299.2 552.16,115.7 186.9,-141.4 368.8,-119.3 384.3,-288.9 355.8,-115 230.4,-507 230.4,-507 l -171.8,0.7 c -211.5,134.7 -231.9,365.9 -231.9,365.9 v 0 c -42.9,-7 -88.6,-10.4 -130,-4.7 -128.42,17.7 -314.78,12 -449.57,-55.9 -134.77,-67.9 -257.66,174.8 -183.59,374.2"
-         style="fill:#8e4a35;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path140" />
-      <path
-         d="m 9962.66,11846 c -40.01,-7 -85.19,-13 -131.38,-15.4 -126.21,-6.7 -260.08,13.2 -317.56,111.9 21.37,175.2 206.11,116.4 332.47,27.6 59.46,-41.8 105.99,-90.3 116.47,-124.1 z m -545.56,136.9 c 0.67,-21.5 3.23,-44.6 7.68,-68.5 32.64,-177.3 166.51,-400.2 396.9,-390.8 17.49,0.6 35.56,2.7 54.17,6.2 101.64,9.1 237.85,32.9 359.15,86.3 173,76.2 315.7,212.9 284.7,454 v 0 c 0,0.2 0,0.4 0,0.6 l -24.4,104.2 v 0.1 l -0.2,0.9 -2.7,11.5 v 0 l -39.1,167.3 -124.6,113 v -0.1 c 1.1,-22.4 15.9,-69.7 27.9,-128.1 23.9,-116.9 36.8,-278.5 -93.3,-374.7 -1,-0.7 -2,-1.4 -3.1,-2.1 -111.4,-71.5 -252.7,10.4 -404.41,76.2 -141.28,61.3 -291.54,108.7 -434.99,5.4 -0.67,-4 -1.27,-7.9 -1.78,-12 v 0 c -1.89,-15.2 -2.53,-31.8 -1.92,-49.4"
-         style="fill:#8e4a35;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path142" />
-      <path
-         d="m 10664.8,12220 c -8.3,-89.2 -73.4,-156 -145.1,-149.3 -71.8,6.8 -123.2,84.6 -114.8,173.8 8.3,89.2 73.4,156 145.1,149.3 71.8,-6.8 123.2,-84.6 114.8,-173.8"
-         style="fill:#f99370;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path144" />
-      <path
-         d="m 10483.1,12316.4 c 2.6,1.4 64,33.4 103.9,4.2 10.2,-7.4 17.7,-18.3 22.7,-32 0.1,0 0.1,-0.2 0.1,-0.2 9.5,-25.9 10.1,-62.6 1.4,-110 -1,-5.1 -5.4,-8.6 -10.4,-8.6 -0.6,0 -1.2,0.1 -1.8,0.2 -5.7,1 -9.5,6.5 -8.4,12.2 6.8,37 7.6,66.5 2.8,88 -58.9,-17.4 -81,-88.8 -81.2,-89.5 -1.3,-4.6 -5.5,-7.5 -10.1,-7.5 -0.9,0 -1.9,0.2 -2.9,0.4 -5.5,1.7 -8.7,7.5 -7.1,13 1.1,3.6 25.2,82.3 94.1,103.3 -3.2,5.7 -6.9,10.4 -11.5,13.8 -29.2,21.6 -81.3,-5.5 -81.8,-5.8 -5.2,-2.7 -11.5,-0.7 -14.2,4.4 -2.7,5.1 -0.7,11.4 4.4,14.1"
-         style="fill:#c16256;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path146" />
-      <path
-         d="m 10953.8,9368.7 h 68 c -1.8,12.5 -2.8,18.9 -2.8,18.9 -2.8,-0.8 -5.6,-1.7 -8.4,-2.5 -16.4,-4.9 -32.9,-9.7 -49.5,-14.3 -2.4,-0.7 -4.9,-1.4 -7.3,-2.1"
-         style="fill:#e8c0a6;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path148" />
-      <path
-         d="m 9697.32,11951.5 c 1.23,0 2.48,0.2 3.69,0.8 4.71,2 6.89,7.5 4.86,12.2 -1.02,2.4 -25.93,58.5 -103.86,65.6 -5.11,0.4 -9.66,-3.4 -10.12,-8.5 -0.47,-5.1 3.31,-9.7 8.44,-10.1 66.47,-6.1 87.56,-52.4 88.43,-54.4 1.53,-3.5 4.96,-5.6 8.56,-5.6"
-         style="fill:#c16256;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path150" />
-      <path
-         d="m 8595.53,11389.9 332.23,-141 c 2.55,1.3 -4.34,141.4 91.81,168.2 105.82,29.5 209.77,155.2 207.71,160.6 33.09,-85 194.49,76.6 139.54,106.9 36.85,34 12.03,72.6 -34.04,95 30.82,29.8 -2.12,65.3 -46.47,79.6 53.72,28.2 97.21,42.5 156.95,60.9 81.81,25.3 27.74,72.2 -20.66,63.8 -395.2,-69 -554,-227.2 -827.07,-594"
-         style="fill:#f99370;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path152" />
-      <path
-         d="m 9593.59,12440.4 c 0.7,0 1.4,0.1 2.1,0.2 92.81,21.4 124.98,94.7 126.31,97.8 2.01,4.8 -0.19,10.2 -4.93,12.3 -4.72,2 -10.19,-0.2 -12.22,-5 -0.39,-0.9 -30.22,-67.8 -113.33,-86.9 -5.02,-1.1 -8.15,-6.1 -7,-11.2 0.99,-4.3 4.83,-7.2 9.07,-7.2"
-         style="fill:#c16256;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path154" />
-      <path
-         d="m 9943.02,12410.9 c 1.72,0 3.46,0.5 5.02,1.5 4.32,2.8 5.59,8.5 2.82,12.9 -1.77,2.7 -44.5,67.9 -140.09,79.9 -5.1,0.6 -9.76,-3 -10.4,-8.1 -0.64,-5.2 2.98,-9.8 8.09,-10.4 86.58,-10.9 126.32,-70.9 126.71,-71.5 1.78,-2.8 4.78,-4.3 7.85,-4.3"
-         style="fill:#c16256;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path156" />
-      <path
-         d="m 8610.66,9306.2 c 265.96,0.7 462.48,190 610.42,458.7 l -44.13,835.4 c 0,0 -257.23,-527.8 -403.46,-999.4 -39.51,-127.4 -98.17,-223 -162.83,-294.7"
-         style="fill:#163356;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path158" />
-      <path
-         d="m 10600,2556 16.7,8.7 c 0,-11.6 14.4,-52.2 26.1,-52.2 l 493.3,-10.1 c 11.7,0 18.9,21.9 18.9,33.6 l 42,12.1 c 0,73.8 -6.1,100.6 -38.7,157.8 -120,158.4 23.3,872.7 19.1,1058.5 29.6,50.9 -519.4,11 -527.1,23 -12.4,0 -22.1,-10.5 -21.1,-22.8 l 64.6,-814.6 c 23.3,-191.2 -93.3,-243.7 -93.8,-394"
-         style="fill:#f99370;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path160" />
-      <path
-         d="m 8461.64,2485.1 h 982.59 c 85.77,3.4 85.11,90.9 69.31,158.7 -54.11,244.5 41.53,806 59.25,1057.5 4.73,46 -31.41,86.1 -77.7,86.1 h -433.66 c -47,0 -83.36,-41.2 -77.51,-87.9 l 78.87,-628.8 c 30.25,-291 -270.75,-315.4 -468.81,-355.5 -77.73,-19.6 -159,-49.8 -196.86,-107.9 -35.35,-51.9 1.7,-122.2 64.52,-122.2"
-         style="fill:#f99370;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path162" />
-      <path
-         d="m 9550.95,2587 c -2.65,-48.2 -26.54,-103.2 -82.35,-102 0.01,0 -1019.21,0 -1019.21,0 -254.18,78 117.8,433.8 576.81,406.9 36.25,-8.7 205.84,-37.7 409.23,-9.5 114.1,11.7 119.73,-195.9 115.52,-295.4"
-         style="fill:#103663;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path164" />
-      <path
-         d="m 11118.9,2485 h -435.6 c -210.5,23.9 -63,404.1 217.7,406.9 282.2,2.8 428.1,-383.4 217.9,-406.9"
-         style="fill:#103663;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path166" />
-      <path
-         d="m 8692.37,2623 c -8.56,0 -16.67,5.1 -20.08,13.5 -39.58,97.6 -111.99,127.1 -112.71,127.4 -26.24,9.9 -10.14,51 15.88,40.3 3.67,-1.4 90.49,-36.8 136.97,-151.4 5.96,-13.9 -5.09,-30.1 -20.06,-29.8"
-         style="fill:#e8c0a6;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path168" />
-      <path
-         d="m 8860.65,2643.3 c -9.24,0 -17.8,6 -20.68,15.3 -34.65,111.9 -132.1,163.6 -133.08,164.1 -25.08,12.5 -4.8,51.8 19.97,38.4 4.65,-2.4 114.54,-60.7 154.48,-189.7 4.48,-13.7 -6.41,-28.3 -20.69,-28.1"
-         style="fill:#e8c0a6;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path170" />
-      <path
-         d="m 9052.17,2666.8 c -8.96,0 -17.35,5.6 -20.45,14.6 -40.44,116.2 -133.84,179.5 -134.77,180.1 -23.54,15.2 0.71,52 23.92,36.1 4.32,-2.8 106.36,-71.5 151.75,-202 5.07,-13.7 -5.89,-29 -20.45,-28.8"
-         style="fill:#e8c0a6;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path172" />
-      <path
-         d="m 11057.2,2762.4 c -165.9,93.4 -312.7,-29.2 -335.9,12.7 -19.5,43.9 197,109.6 346.9,27.7 19,-10.3 10.3,-41.2 -11,-40.4"
-         style="fill:#e8c0a6;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path174" />
-      <path
-         d="m 8378.07,2587 h 1172.88 c -4.32,-35.8 -14.21,-70.6 -32.16,-102 h -1069.4 c -52.67,0 -90.02,52.8 -71.32,102"
-         style="fill:#0f2e54;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path176" />
-      <path
-         d="m 11118.9,2485 h -435.6 c -55.5,0 -100.1,46.7 -96.7,102 h 628.9 c 3.3,-55.3 -41.2,-102 -96.6,-102"
-         style="fill:#0f2e54;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path178" />
-      <path
-         d="m 11246.1,3040.9 c 0,0 -464.6,-112.8 -703.9,8.4 -124.6,781.3 -470.4,2956.6 -590.88,4447.3 -4.61,-86.9 -257.67,-3592.4 -305.83,-4447.3 -165.26,-55.3 -497.54,-122 -683.5,12 -83.53,899.9 -351.75,3862.6 52.28,6282.3 0,0 1107.23,-123.2 1971.83,138.1 238,-767.6 301.1,-5519.7 260,-6440.8"
-         style="fill:#3a72aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path180" />
-      <path
-         d="m 9140.74,3136 c -224.73,2600.1 41.06,4812.4 107.6,4837.1 48.79,-11.2 -229.02,-2260.7 -107.6,-4837.1"
-         style="fill:#23659b;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path182" />
-      <path
-         d="m 10880.6,3136 c -155,2664.4 -546.1,5148.6 -499.9,5184.2 59.4,3.5 456.2,-2537.1 499.9,-5184.2"
-         style="fill:#23659b;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path184" />
-      <path
-         d="m 11147.2,8437 c -39.5,-48.1 -81.7,-96.3 -126.3,-144.7 0,0 -217.6,-40.9 -387.9,185.7 694.2,1501.4 -644.43,1583.5 -378.5,2919.6 896.2,-105.8 2142.8,-1443.3 892.7,-2960.6"
-         style="fill:#1d3f70;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path186" />
-      <path
-         d="m 11147.2,8437 c -39.5,-48.1 -81.7,-96.3 -126.3,-144.7 0,0 -217.6,-40.9 -387.9,185.7 20.3,72.3 50.6,115 71.9,175.4 0,0 129.7,-152.1 442.3,-216.4"
-         style="fill:#163356;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path188" />
-      <path
-         d="m 11036.5,8263.1 c -374.1,-22.6 -559,372.3 -407.8,279.8 3.8,-9.9 95.5,-237.2 440.3,-222.2 54.4,-10.8 31.9,-69.4 -32.5,-57.6"
-         style="fill:#23659b;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path190" />
-      <path
-         d="m 8853.28,8303.4 c 0,0 67.63,-290.1 608.82,-433.2 155.01,-41 244.59,-20.7 267.32,86.7 11.41,54 40.87,147.9 95.05,182.7 0,0 121.09,-52.3 166.78,-126.5 100.15,-162.6 251.15,-14.8 324.55,155.4 90.9,210.6 321.2,389 371.5,565.6 L 8853.28,8303.4"
-         style="fill:#f4d4be;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path192" />
-      <path
-         d="m 11058.6,8662 c -17.6,-31.2 -28.1,-26.2 -46.1,-8.2 -486.4,363.1 -660.3,-430.3 -1184.15,-444.4 -533.25,-52.8 -829.88,-82.9 -975.12,94 -253.58,393.1 149.74,2150 475.96,2575.5 142.9,221.2 363.68,436.8 500.2,551.6 -2.79,-11.5 -52.7,-314.7 415.21,-15.5 23.5,-9.9 181.8,-172.1 172.5,-249.5 23.7,-355.7 867.7,-2103.9 641.5,-2503.5"
-         style="fill:#1d3f70;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path194" />
-      <path
-         d="m 10777.2,8550.3 -106.6,22.1 c 426.2,959.4 -75,1365 -340.1,1905.5 614.8,-711.5 707.7,-1101.5 446.7,-1927.6"
-         style="fill:#163356;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path196" />
-      <path
-         d="m 10398.4,11371.9 c 2.6,-178.5 -455.34,-336.1 -481.29,-336.3 l -54.89,162.4 c -70.47,-17.4 -132.52,-116 -132.52,-116 -190.04,185.4 -98.86,296.8 -51.23,319.6 55.04,26.3 151.04,29.1 150.92,28.9 -2.82,-11.5 -10.24,-286.6 415.21,-15.5 54.7,25.4 153.8,-43.1 153.8,-43.1"
-         style="fill:#f4d4be;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path198" />
-      <path
-         d="m 9645.49,3049.3 c 0.43,0.8 -60.07,-22.3 -143.43,-38.1 0,0 233.44,3478.8 268.22,3943.1 34.77,464.2 181.04,542.3 181.04,542.3 0,0 -309.7,-4372.1 -305.83,-4447.3"
-         style="fill:#23659b;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path200" />
-      <path
-         d="m 9654.69,3218 c -6.25,-100.4 -9.66,-160.4 -9.2,-168.7 -165.26,-55.3 -497.54,-122 -683.5,12 0,0 -5.91,55.1 -15.57,156.7 0,0 325.72,-149.8 708.27,0"
-         style="fill:#23659b;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path202" />
-      <path
-         d="m 11246.1,3040.9 c 0,0 -464.6,-112.8 -703.9,8.4 0,0 -9.9,60.5 -27.2,168.7 0,0 327.3,-91.7 736.8,0 1.8,-105.5 -7.1,-168.3 -5.7,-177.1"
-         style="fill:#23659b;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path204" />
-      <path
-         d="m 8510.61,11302.9 c 1.88,-2.6 3.76,-5.2 5.82,-7.7 152.9,-196.5 402.43,-187.3 402.43,-187.3 5.65,48.4 8.9,91.7 8.9,126.5 -32.33,-1.7 -217.21,-8.7 -346,155.5 -5.13,-6.3 -31.81,-36.4 -71.15,-87"
-         style="fill:#163356;fill-opacity:1;fill-rule:nonzero;stroke:none"
-         id="path206" />
-    </g>
-  </g>
-</svg>
diff --git a/frontend/assets/gen-lifebelt.svg b/frontend/assets/gen-lifebelt.svg
new file mode 100644
index 0000000..c32fcef
--- /dev/null
+++ b/frontend/assets/gen-lifebelt.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>gen-lifebelt</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="General" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="SLICES-64px">
+
+</g>
+        <g id="ICONS" transform="translate(5.000000, 5.000000)">
+            <g id="gen-lifebelt" transform="translate(0.000000, 2.000000)">
+                <path d="M26.0001,40 C18.2681,40 12.0001,33.732 12.0001,26 C12.0001,18.267 18.2681,12 26.0001,12 C33.7321,12 40.0001,18.267 40.0001,26 C40.0001,33.732 33.7321,40 26.0001,40 M26.0001,0 C11.6411,0 0.0001,11.64 0.0001,26 C0.0001,40.359 11.6411,52 26.0001,52 C40.3591,52 52.0001,40.359 52.0001,26 C52.0001,11.64 40.3591,0 26.0001,0" id="Fill-464" fill="#F16963">
+
+</path>
+                <path d="M3.0025,13.8716 L13.6385,19.4216 L13.6485,19.4116 C14.9905,16.9016 17.0765,14.8566 19.6105,13.5526 L19.6385,13.5256 L13.8725,3.0026 C9.2455,5.4476 5.4475,9.2456 3.0025,13.8716" id="Fill-465" fill="#F1F0E2">
+
+</path>
+                <path d="M38.128,3.0022 L32.361,13.5252 L32.39,13.5532 C34.923,14.8562 37.01,16.9012 38.352,19.4122 L38.361,19.4212 L48.998,13.8712 C46.553,9.2452 42.754,5.4472 38.128,3.0022" id="Fill-466" fill="#F1F0E2">
+
+</path>
+                <path d="M13.648,32.5872 L13.639,32.5782 L3.002,38.1282 C5.447,42.7542 9.246,46.5532 13.872,48.9972 L19.639,38.4742 L19.611,38.4472 C17.077,37.1442 14.99,35.0982 13.648,32.5872" id="Fill-467" fill="#F1F0E2">
+
+</path>
+                <path d="M48.9976,38.1284 L38.3616,32.5774 L38.3516,32.5864 C37.0106,35.0974 34.9236,37.1434 32.3896,38.4474 L32.3616,38.4744 L38.1276,48.9974 C42.7546,46.5524 46.5526,42.7544 48.9976,38.1284" id="Fill-468" fill="#F1F0E2">
+
+</path>
+                <path d="M2.9971,13.8689 C2.3621,12.7229 2.0001,11.4029 2.0001,9.9999 C2.0001,5.5819 5.5821,1.9999 10.0001,1.9999 C11.4031,1.9999 12.7231,2.3619 13.8691,2.9969" id="Stroke-469" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M49.003,13.8689 C49.638,12.7229 50,11.4029 50,9.9999 C50,5.5819 46.418,1.9999 42,1.9999 C40.597,1.9999 39.277,2.3619 38.131,2.9969" id="Stroke-470" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M2.9971,38.1311 C2.3621,39.2771 2.0001,40.5961 2.0001,42.0001 C2.0001,46.4171 5.5821,50.0001 10.0001,50.0001 C11.4031,50.0001 12.7231,49.6381 13.8691,49.0031" id="Stroke-471" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M49.003,38.1311 C49.638,39.2771 50,40.5961 50,42.0001 C50,46.4171 46.418,50.0001 42,50.0001 C40.597,50.0001 39.277,49.6381 38.131,49.0031" id="Stroke-472" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M52.0001,26 C52.0001,11.64 40.3591,0 26.0001,0 C11.6411,0 0.0001,11.64 0.0001,26 C0.0001,40.359 11.6411,52 26.0001,52 C40.3591,52 52.0001,40.359 52.0001,26 Z" id="Stroke-473" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M40.0001,26 C40.0001,33.732 33.7321,40 26.0001,40 C18.2681,40 12.0001,33.732 12.0001,26 C12.0001,18.267 18.2681,12 26.0001,12 C33.7321,12 40.0001,18.267 40.0001,26 Z" id="Stroke-474" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M13.8692,2.9968 L19.6392,13.5248" id="Stroke-475" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M13.6387,19.4216 L2.9967,13.8686" id="Stroke-476" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M38.1309,2.9968 L32.3609,13.5248" id="Stroke-477" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M38.3614,19.4216 L49.0034,13.8686" id="Stroke-478" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M13.8692,49.0027 L19.6392,38.4747" id="Stroke-479" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M13.6387,32.5779 L2.9967,38.1309" id="Stroke-480" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M38.1309,49.0027 L32.3609,38.4747" id="Stroke-481" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+                <path d="M38.3614,32.5779 L49.0034,38.1309" id="Stroke-482" stroke="#414547" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/frontend/assets/plan.svg b/frontend/assets/plan.svg
deleted file mode 100644
index 62705c9..0000000
--- a/frontend/assets/plan.svg
+++ /dev/null
@@ -1,161 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 viewBox="0 0 2200 2200" style="enable-background:new 0 0 2200 2200;" xml:space="preserve">
-
-<g id="Objects">
-	<g>
-		<path style="fill:#788D8E;" d="M1202.178,2002.073c-5.328,0-9.648-4.319-9.649-9.647c-0.001-5.328,4.319-9.649,9.647-9.649
-			c9.63-0.001,19.271-0.006,28.918-0.014c0.003,0,0.006,0,0.009,0c5.325,0,9.643,4.314,9.647,9.639
-			c0.005,5.328-4.311,9.651-9.639,9.656C1221.458,2002.068,1211.813,2002.072,1202.178,2002.073z M1144.298,2002.03
-			c-0.006,0-0.01,0-0.016,0c-9.658-0.015-19.305-0.036-28.94-0.061c-5.328-0.014-9.636-4.345-9.622-9.673
-			c0.014-5.319,4.331-9.622,9.648-9.622c0.008,0,0.017,0,0.025,0c9.628,0.025,19.269,0.046,28.919,0.061
-			c5.328,0.009,9.641,4.335,9.632,9.663C1153.937,1997.721,1149.619,2002.03,1144.298,2002.03z M1288.979,2001.966
-			c-5.317,0-9.634-4.306-9.647-9.626c-0.012-5.328,4.298-9.657,9.626-9.669c9.634-0.022,19.274-0.047,28.923-0.075
-			c5.297,0.018,9.66,4.292,9.676,9.619c0.015,5.328-4.291,9.66-9.619,9.676c-9.652,0.028-19.299,0.054-28.936,0.075
-			C1288.994,2001.966,1288.986,2001.966,1288.979,2001.966z M1057.498,2001.759c-0.015,0-0.03,0-0.045,0
-			c-9.659-0.044-19.306-0.095-28.939-0.152c-5.328-0.031-9.622-4.376-9.591-9.704c0.031-5.309,4.344-9.591,9.646-9.591
-			c0.02,0,0.04,0,0.058,0c9.625,0.057,19.263,0.107,28.914,0.152c5.328,0.025,9.628,4.364,9.603,9.692
-			C1067.12,1997.468,1062.805,2001.759,1057.498,2001.759z M1375.787,2001.691c-5.31,0-9.625-4.293-9.647-9.609
-			c-0.022-5.328,4.281-9.665,9.609-9.686c9.636-0.039,19.28-0.079,28.928-0.123c0.015,0,0.029,0,0.044,0
-			c5.308,0,9.623,4.291,9.647,9.604c0.024,5.328-4.276,9.666-9.604,9.691c-9.651,0.043-19.297,0.084-28.937,0.122
-			C1375.813,2001.691,1375.8,2001.691,1375.787,2001.691z M1462.601,2001.29c-5.305,0-9.619-4.287-9.647-9.598
-			c-0.027-5.328,4.27-9.67,9.598-9.698c9.641-0.05,19.285-0.102,28.932-0.156c0.018,0,0.037,0,0.056,0
-			c5.302,0,9.616,4.284,9.646,9.594c0.029,5.328-4.266,9.671-9.594,9.701c-9.649,0.054-19.297,0.105-28.94,0.156
-			C1462.635,2001.29,1462.618,2001.29,1462.601,2001.29z M970.707,2001.198c-0.027,0-0.054,0-0.081,0
-			c-9.662-0.079-19.308-0.166-28.939-0.259c-5.328-0.052-9.605-4.413-9.554-9.741c0.052-5.296,4.361-9.554,9.646-9.554
-			c0.032,0,0.063,0,0.095,0.001c9.621,0.093,19.258,0.179,28.911,0.258c5.328,0.044,9.612,4.399,9.568,9.727
-			C980.31,1996.93,975.998,2001.198,970.707,2001.198z M1549.42,2000.802c-5.301,0-9.614-4.281-9.646-9.59
-			c-0.032-5.328,4.262-9.673,9.59-9.705l28.936-0.176c0.021,0,0.042,0,0.061,0c5.301,0,9.614,4.279,9.647,9.587
-			c0.033,5.328-4.259,9.674-9.587,9.708l-28.942,0.176C1549.459,2000.802,1549.439,2000.802,1549.42,2000.802z M883.923,2000.297
-			c-0.041,0-0.083,0-0.124-0.001c-9.663-0.122-19.308-0.25-28.935-0.385c-5.328-0.075-9.586-4.454-9.511-9.782
-			c0.075-5.328,4.464-9.604,9.782-9.511c9.617,0.136,19.254,0.264,28.907,0.385c5.328,0.067,9.592,4.44,9.525,9.768
-			C893.501,1996.057,889.195,2000.297,883.923,2000.297z M1636.244,2000.264c-5.3,0-9.612-4.279-9.646-9.586
-			c-0.034-5.328,4.258-9.675,9.586-9.709l28.943-0.184c0.021,0,0.042,0,0.062,0c5.3,0,9.613,4.279,9.647,9.586
-			c0.034,5.328-4.259,9.675-9.586,9.709l-28.943,0.184C1636.286,2000.264,1636.265,2000.264,1636.244,2000.264z M1723.075,1999.719
-			c-5.3,0-9.614-4.28-9.647-9.588c-0.033-5.328,4.26-9.674,9.588-9.707l28.946-0.177c0.02,0,0.04,0,0.059,0
-			c5.301,0,9.615,4.28,9.647,9.589c0.032,5.328-4.261,9.674-9.589,9.706l-28.945,0.177
-			C1723.115,1999.719,1723.095,1999.719,1723.075,1999.719z M1809.912,1999.201c-5.303,0-9.616-4.283-9.647-9.593
-			c-0.03-5.328,4.265-9.672,9.593-9.702l28.952-0.16c0.018,0,0.036,0,0.053,0c5.304,0,9.618,4.285,9.647,9.596
-			c0.028,5.328-4.268,9.67-9.596,9.699l-28.947,0.16C1809.949,1999.201,1809.931,1999.201,1809.912,1999.201z M797.15,1998.997
-			c-0.057,0-0.115-0.001-0.172-0.002c-9.665-0.169-19.31-0.346-28.935-0.531c-5.327-0.103-9.562-4.504-9.459-9.832
-			c0.104-5.327,4.48-9.533,9.832-9.459c9.612,0.186,19.245,0.363,28.899,0.531c5.327,0.092,9.57,4.487,9.477,9.814
-			C806.701,1994.788,802.399,1998.997,797.15,1998.997z M1896.756,1998.75c-5.307,0-9.621-4.29-9.647-9.602
-			c-0.025-5.328,4.274-9.667,9.602-9.693c9.658-0.045,19.31-0.089,28.958-0.129c0.014,0,0.027,0,0.041,0
-			c5.309,0,9.624,4.292,9.647,9.607c0.023,5.328-4.279,9.666-9.607,9.688c-9.644,0.041-19.294,0.084-28.948,0.129
-			C1896.787,1998.75,1896.771,1998.75,1896.756,1998.75z M710.388,1997.237c-0.076,0-0.152-0.001-0.228-0.003
-			c-9.667-0.223-19.311-0.457-28.932-0.7c-5.326-0.135-9.535-4.562-9.401-9.889c0.133-5.243,4.425-9.404,9.64-9.404
-			c0.083,0,0.166,0.001,0.249,0.003c9.607,0.243,19.237,0.477,28.891,0.7c5.327,0.122,9.545,4.541,9.421,9.868
-			C719.907,1993.064,715.612,1997.237,710.388,1997.237z M623.642,1994.948c-0.096,0-0.193-0.001-0.29-0.004
-			c-9.67-0.287-19.314-0.585-28.929-0.894c-5.326-0.172-9.503-4.628-9.333-9.953c0.171-5.325,4.65-9.465,9.953-9.333
-			c9.6,0.309,19.227,0.607,28.88,0.892c5.326,0.158,9.516,4.604,9.357,9.93C633.126,1990.815,628.838,1994.948,623.642,1994.948z
-			 M536.937,1991.683c-0.226,0-0.453-0.007-0.682-0.024c-10.955-0.765-20.624-1.8-29.559-3.167
-			c-5.267-0.806-8.883-5.728-8.078-10.995c0.805-5.268,5.725-8.888,10.995-8.078c8.408,1.286,17.563,2.264,27.985,2.992
-			c5.316,0.371,9.323,4.981,8.952,10.296C546.196,1987.794,541.959,1991.683,536.937,1991.683z M452.936,1972.044
-			c-1.444,0-2.91-0.325-4.291-1.012c-5.129-2.553-10.134-5.398-14.875-8.458c-3.821-2.466-7.597-5.17-11.224-8.036
-			c-4.179-3.305-4.889-9.372-1.585-13.552c3.305-4.18,9.371-4.889,13.552-1.585c3.144,2.486,6.415,4.828,9.719,6.961
-			c4.142,2.673,8.519,5.162,13.01,7.397c4.77,2.373,6.713,8.165,4.34,12.935C459.893,1970.083,456.481,1972.044,452.936,1972.044z
-			 M390.843,1913.094c-3.257,0-6.436-1.65-8.252-4.636c-5.088-8.366-9.753-17.406-13.866-26.869
-			c-2.125-4.886,0.115-10.57,5.002-12.693c4.884-2.125,10.569,0.114,12.694,5.002c3.765,8.661,8.023,16.915,12.657,24.534
-			c2.768,4.552,1.323,10.487-3.23,13.256C394.28,1912.639,392.55,1913.094,390.843,1913.094z M360.798,1832.103
-			c-4.545,0-8.593-3.227-9.469-7.857c-1.832-9.681-3.208-19.642-4.092-29.605c-0.471-5.307,3.45-9.991,8.757-10.463
-			c5.305-0.466,9.991,3.449,10.462,8.757c0.828,9.335,2.117,18.663,3.831,27.724c0.99,5.236-2.451,10.282-7.686,11.272
-			C361.996,1832.047,361.393,1832.103,360.798,1832.103z M357.3,1745.636c-0.337,0-0.677-0.018-1.02-0.054
-			c-5.299-0.557-9.143-5.304-8.586-10.603c1.051-10.004,2.612-19.95,4.636-29.561c1.098-5.214,6.217-8.55,11.429-7.451
-			c5.214,1.099,8.55,6.215,7.451,11.429c-1.889,8.965-3.345,18.252-4.327,27.6C366.362,1741.952,362.175,1745.636,357.3,1745.636z
-			 M379.592,1662.099c-1.292,0-2.604-0.261-3.863-0.812c-4.881-2.136-7.107-7.824-4.97-12.706
-			c3.967-9.067,8.429-18.064,13.26-26.742c2.591-4.655,8.466-6.329,13.122-3.737c4.656,2.592,6.329,8.466,3.737,13.122
-			c-4.533,8.143-8.72,16.585-12.442,25.091C386.85,1659.939,383.308,1662.099,379.592,1662.099z M425.149,1588.527
-			c-2.174,0-4.36-0.73-6.162-2.228c-4.097-3.407-4.658-9.489-1.252-13.587c6.291-7.567,13.033-14.977,20.039-22.024
-			c3.756-3.78,9.865-3.796,13.644-0.039c3.778,3.756,3.796,9.865,0.039,13.643c-6.604,6.642-12.958,13.624-18.884,20.754
-			C430.666,1587.342,427.917,1588.527,425.149,1588.527z M488.757,1529.81c-3.021,0-5.994-1.414-7.875-4.063
-			c-3.085-4.345-2.062-10.367,2.282-13.452c8.036-5.705,16.424-11.148,24.935-16.182c4.587-2.711,10.502-1.194,13.215,3.393
-			c2.712,4.586,1.194,10.503-3.393,13.215c-8.051,4.762-15.987,9.912-23.588,15.308
-			C492.639,1529.232,490.688,1529.81,488.757,1529.81z M565.026,1488.849c-3.858,0-7.5-2.33-8.989-6.14
-			c-1.939-4.962,0.513-10.558,5.476-12.497c8.996-3.515,18.386-6.814,27.91-9.805c5.085-1.593,10.499,1.23,12.094,6.314
-			c1.597,5.083-1.229,10.498-6.313,12.095c-9.107,2.86-18.081,6.012-26.67,9.368
-			C567.381,1488.636,566.194,1488.849,565.026,1488.849z M648.419,1465.236c-4.529,0-8.569-3.204-9.462-7.816
-			c-1.012-5.232,2.408-10.293,7.639-11.306c9.243-1.788,18.981-3.446,28.945-4.926c5.268-0.786,10.177,2.855,10.961,8.125
-			c0.783,5.27-2.855,10.178-8.125,10.961c-9.686,1.439-19.145,3.049-28.114,4.784
-			C649.644,1465.178,649.027,1465.236,648.419,1465.236z M734.448,1453.776c-4.949,0-9.161-3.786-9.599-8.809
-			c-0.464-5.308,3.463-9.987,8.771-10.45c8.927-0.779,18.419-1.521,29.019-2.265c5.285-0.369,9.926,3.633,10.3,8.948
-			c0.373,5.315-3.633,9.926-8.948,10.299c-10.489,0.737-19.875,1.469-28.691,2.239
-			C735.013,1453.764,734.729,1453.776,734.448,1453.776z M821.074,1447.866c-5.059,0-9.308-3.941-9.621-9.059
-			c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.767c5.341-0.318,9.893,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
-			l-28.889,1.766C821.471,1447.86,821.272,1447.866,821.074,1447.866z M907.74,1442.568c-5.059,0-9.308-3.941-9.621-9.059
-			c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.766c5.344-0.326,9.893,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.218
-			l-28.889,1.767C908.137,1442.562,907.938,1442.568,907.74,1442.568z M994.406,1437.269c-5.059,0-9.307-3.941-9.62-9.059
-			c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.766c5.345-0.309,9.893,3.722,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
-			l-28.889,1.767C994.805,1437.263,994.604,1437.269,994.406,1437.269z M1081.072,1431.969c-5.059,0-9.307-3.941-9.62-9.059
-			c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.766c5.322-0.318,9.894,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
-			l-28.889,1.767C1081.47,1431.964,1081.27,1431.969,1081.072,1431.969z M1167.738,1426.671c-5.059,0-9.307-3.941-9.62-9.059
-			c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.767c5.349-0.326,9.894,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
-			l-28.889,1.766C1168.135,1426.665,1167.936,1426.671,1167.738,1426.671z M1254.358,1420.693c-4.914,0-9.115-3.738-9.592-8.73
-			c-0.508-5.304,3.38-10.015,8.685-10.523c10.205-0.975,19.481-2.043,28.357-3.264c5.276-0.72,10.146,2.966,10.872,8.244
-			c0.725,5.279-2.966,10.146-8.244,10.872c-9.142,1.257-18.676,2.354-29.148,3.356
-			C1254.976,1420.678,1254.665,1420.693,1254.358,1420.693z M1339.835,1406.05c-4.233,0-8.115-2.807-9.295-7.086
-			c-1.416-5.136,1.6-10.448,6.735-11.864c9.242-2.549,18.223-5.456,26.694-8.639c4.994-1.875,10.551,0.65,12.425,5.636
-			c1.875,4.988-0.649,10.55-5.636,12.425c-9.014,3.388-18.553,6.476-28.353,9.178
-			C1341.548,1405.937,1340.684,1406.05,1339.835,1406.05z M1418.99,1371.212c-3.131,0-6.201-1.522-8.057-4.329
-			c-2.938-4.445-1.716-10.43,2.729-13.368c7.542-4.985,14.948-10.622,22.014-16.754c4.022-3.493,10.115-3.063,13.609,0.962
-			c3.493,4.024,3.062,10.117-0.962,13.609c-7.698,6.683-15.781,12.832-24.022,18.28
-			C1422.663,1370.694,1420.817,1371.212,1418.99,1371.212z M1480.743,1310.868c-1.931,0-3.882-0.578-5.577-1.782
-			c-4.344-3.086-5.366-9.108-2.281-13.452c5.366-7.558,10.318-15.487,14.721-23.567c2.549-4.679,8.41-6.406,13.087-3.856
-			c4.679,2.549,6.406,8.409,3.856,13.087c-4.765,8.747-10.126,17.328-15.932,25.506
-			C1486.737,1309.454,1483.762,1310.868,1480.743,1310.868z M1517.216,1232.602c-0.778,0-1.568-0.094-2.356-0.292
-			c-5.169-1.297-8.306-6.538-7.009-11.707c2.256-8.984,3.898-18.121,4.878-27.155c0.575-5.299,5.342-9.13,10.632-8.55
-			c5.298,0.575,9.126,5.335,8.55,10.633c-1.076,9.911-2.875,19.928-5.346,29.771
-			C1525.467,1229.681,1521.535,1232.602,1517.216,1232.602z M1520.169,1146.498c-4.554,0-8.606-3.239-9.472-7.879
-			c-1.672-8.957-4.032-17.905-7.015-26.593c-1.731-5.04,0.953-10.527,5.992-12.257c5.036-1.729,10.528,0.953,12.257,5.992
-			c3.287,9.575,5.889,19.438,7.733,29.318c0.978,5.237-2.475,10.276-7.713,11.254
-			C1521.352,1146.444,1520.757,1146.498,1520.169,1146.498z M1486.631,1067.128c-3.053,0-6.055-1.445-7.93-4.142
-			c-5.223-7.514-11.025-14.791-17.243-21.63c-3.585-3.942-3.295-10.044,0.647-13.629c3.942-3.584,10.044-3.295,13.628,0.648
-			c6.781,7.457,13.11,15.396,18.811,23.597c3.041,4.375,1.961,10.387-2.415,13.428
-			C1490.452,1066.568,1488.532,1067.128,1486.631,1067.128z M1424.593,1007.152c-1.794,0-3.608-0.499-5.227-1.546
-			c-7.728-4.995-15.75-9.441-23.845-13.217l-0.314-0.146c-4.827-2.257-6.911-7.999-4.653-12.826c2.257-4.826,8-6.91,12.825-4.653
-			l0.276,0.129c8.915,4.158,17.716,9.036,26.183,14.508c4.475,2.892,5.758,8.864,2.866,13.339
-			C1430.859,1005.596,1427.759,1007.152,1424.593,1007.152z M1344.533,974.803c-0.7,0-1.41-0.076-2.123-0.236
-			c-8.759-1.966-18.077-3.643-27.693-4.985c-5.277-0.736-8.958-5.611-8.222-10.888c0.737-5.277,5.615-8.957,10.888-8.222
-			c10.137,1.415,19.98,3.187,29.254,5.268c5.199,1.167,8.467,6.327,7.3,11.527C1352.93,971.754,1348.947,974.803,1344.533,974.803z
-			 M274.324,966.773c-5.318,0-9.634-4.305-9.647-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.016,0,0.023,0
-			c5.317,0,9.634,4.305,9.647,9.625c0.012,5.328-4.297,9.657-9.625,9.67l-28.943,0.066
-			C274.339,966.773,274.331,966.773,274.324,966.773z M361.152,966.573c-5.318,0-9.635-4.305-9.647-9.625
-			c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c5.338-0.002,9.657,4.297,9.67,9.625s-4.297,9.657-9.625,9.67l-28.943,0.066
-			C361.167,966.573,361.16,966.573,361.152,966.573z M447.979,966.373c-5.318,0-9.634-4.305-9.647-9.625
-			c-0.012-5.328,4.297-9.657,9.625-9.67l28.942-0.066c0.008,0,0.015,0,0.023,0c5.318,0,9.635,4.305,9.648,9.625
-			c0.012,5.328-4.297,9.657-9.626,9.67l-28.942,0.066C447.995,966.373,447.987,966.373,447.979,966.373z M534.808,966.174
-			c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0
-			c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
-			C534.823,966.174,534.815,966.174,534.808,966.174z M621.636,965.973c-5.318,0-9.635-4.305-9.648-9.625
-			c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0c5.318,0,9.635,4.305,9.648,9.625
-			c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066C621.651,965.973,621.643,965.973,621.636,965.973z M708.463,965.774
-			c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0
-			c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
-			C708.478,965.774,708.471,965.774,708.463,965.774z M795.291,965.574c-5.318,0-9.635-4.305-9.648-9.625
-			c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c5.292,0.018,9.658,4.297,9.67,9.625c0.012,5.328-4.297,9.657-9.626,9.67
-			l-28.943,0.066C795.306,965.574,795.299,965.574,795.291,965.574z M882.12,965.374c-5.318,0-9.635-4.305-9.648-9.625
-			c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.016,0,0.024,0c5.317,0,9.634,4.305,9.647,9.625
-			c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066C882.135,965.374,882.127,965.374,882.12,965.374z M968.947,965.174
-			c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0
-			c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
-			C968.962,965.174,968.955,965.174,968.947,965.174z M1258.376,965.13c-0.103,0-0.204-0.001-0.307-0.005
-			c-8.629-0.27-17.745-0.424-28.69-0.483c-5.328-0.029-9.623-4.372-9.595-9.7c0.029-5.31,4.342-9.595,9.647-9.595
-			c0.018,0,0.036,0,0.054,0c11.114,0.06,20.389,0.216,29.188,0.492c5.326,0.167,9.508,4.619,9.341,9.945
-			C1267.849,961.007,1263.564,965.13,1258.376,965.13z M1055.775,964.974c-5.318,0-9.635-4.305-9.648-9.625
-			c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.016,0,0.024,0c5.318,0,9.634,4.305,9.647,9.625
-			c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066C1055.79,964.974,1055.783,964.974,1055.775,964.974z M1142.603,964.775
-			c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.007,0,0.015,0,0.023,0
-			c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
-			C1142.619,964.775,1142.611,964.775,1142.603,964.775z"/>
-		<path style="fill:#D13737;" d="M462.452,197.927c-156.647,0-283.638,126.991-283.638,283.638
-			c0,251.801,283.638,464.048,283.638,464.048S746.09,733.366,746.09,481.565C746.09,324.918,619.099,197.927,462.452,197.927z
-			 M462.316,679.485c-109.374,0-198.045-88.671-198.045-198.055c0-109.374,88.671-198.045,198.045-198.045
-			c109.384,0,198.055,88.671,198.055,198.045C660.371,590.814,571.701,679.485,462.316,679.485z"/>
-		<path style="fill:#18ACB7;" d="M1737.548,1228.212c-156.647,0-283.638,126.991-283.638,283.638
-			c0,251.801,283.638,464.048,283.638,464.048s283.638-212.246,283.638-464.048
-			C2021.187,1355.203,1894.196,1228.212,1737.548,1228.212z M1737.413,1709.77c-109.374,0-198.045-88.671-198.045-198.055
-			c0-109.374,88.671-198.045,198.045-198.045c109.384,0,198.055,88.671,198.055,198.045
-			C1935.468,1621.1,1846.797,1709.77,1737.413,1709.77z"/>
-	</g>
-</g>
-</svg>
diff --git a/frontend/assets/terms_and_conditions.md b/frontend/assets/terms_and_conditions.md
new file mode 100644
index 0000000..924a4ed
--- /dev/null
+++ b/frontend/assets/terms_and_conditions.md
@@ -0,0 +1,126 @@
+# Terms and Conditions
+
+> Last updated: January 09, 2025
+>
+> Also see: https://anydev.info/terms-and-conditions/
+
+Please read these terms and conditions carefully before using our Service.
+
+## Interpretation and Definitions
+### Interpretation
+
+The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.
+
+### Definitions
+
+For the purposes of these Terms and Conditions:
+  - **Application** means the software program provided by the Company downloaded by You on any electronic device, named AnyWay
+  - **Application Store** means the digital distribution service operated and developed by Apple Inc. (Apple App Store) or Google Inc. (Google Play Store) in which the Application has been downloaded.
+  - **Affiliate** means an entity that controls, is controlled by or is under common control with a party, where "control" means ownership of 50% or more of the shares, equity interest or other securities entitled to vote for election of directors or other managing authority.
+  - **Country** refers to: Switzerland
+  - **Company** (referred to as either "the Company", "We", "Us" or "Our" in this Agreement) refers to AnyDev.
+  - **Device** means any device that can access the Service such as a computer, a cellphone or a digital tablet.
+  - **Service** refers to the Application.
+  - **Terms and Conditions** (also referred as "Terms") mean these Terms and Conditions that form the entire agreement between You and the Company regarding the use of the Service. This Terms and Conditions agreement has been created with the help of the Terms and Conditions Generator.
+  - **Third-party Social Media Service** means any services or content (including data, information, products or services) provided by a third-party that may be displayed, included or made available by the Service.
+  - **You** means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable.
+
+## Acknowledgment
+
+These are the Terms and Conditions governing the use of this Service and the agreement that operates between You and the Company. These Terms and Conditions set out the rights and obligations of all users regarding the use of the Service.
+
+Your access to and use of the Service is conditioned on Your acceptance of and compliance with these Terms and Conditions. These Terms and Conditions apply to all visitors, users and others who access or use the Service.
+
+By accessing or using the Service You agree to be bound by these Terms and Conditions. If You disagree with any part of these Terms and Conditions then You may not access the Service.
+
+You represent that you are over the age of 18. The Company does not permit those under 18 to use the Service.
+
+Your access to and use of the Service is also conditioned on Your acceptance of and compliance with the Privacy Policy of the Company. Our Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your personal information when You use the Application or the Website and tells You about Your privacy rights and how the law protects You. Please read Our Privacy Policy carefully before using Our Service.
+
+
+## Links to Other Websites
+
+Our Service may contain links to third-party web sites or services that are not owned or controlled by the Company.
+
+The Company has no control over, and assumes no responsibility for, the content, privacy policies, or practices of any third party web sites or services. You further acknowledge and agree that the Company shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with the use of or reliance on any such content, goods or services available on or through any such web sites or services.
+
+We strongly advise You to read the terms and conditions and privacy policies of any third-party web sites or services that You visit.
+
+
+## Termination
+
+We may terminate or suspend Your access immediately, without prior notice or liability, for any reason whatsoever, including without limitation if You breach these Terms and Conditions.
+
+Upon termination, Your right to use the Service will cease immediately.
+
+
+## Limitation of Liability
+
+Notwithstanding any damages that You might incur, the entire liability of the Company and any of its suppliers under any provision of this Terms and Your exclusive remedy for all of the foregoing shall be limited to the amount actually paid by You through the Service or 100 USD if You haven't purchased anything through the Service.
+
+To the maximum extent permitted by applicable law, in no event shall the Company or its suppliers be liable for any special, incidental, indirect, punitive, or consequential damages whatsoever (including, but not limited to, damages for loss of profits, loss of data, loss of use, loss of goodwill, business interruption, personal injury, loss of privacy, or any other pecuniary or non-pecuniary loss or damage) arising out of or in any way related to the use of or inability to use the Service, third-party software and/or third-party hardware used with the Service, or otherwise in connection with any provision of this Terms, even if the Company or any supplier has been advised of the possibility of such damages and even if the remedy fails of its essential purpose.
+
+In particular, the Company and its suppliers are not liable for any damages or losses that may arise from:
+  - Your reliance on any content provided through the Service;
+  - Errors, mistakes, or inaccuracies of content;
+  - Any unauthorized access to or use of our servers and/or any personal information stored therein;
+  - Any interruption or cessation of transmission to or from the Service;
+  - Any bugs, viruses, trojan horses, or the like which may be transmitted to or through the Service by any third party;
+  - Any errors or omissions in any content or for any loss or damage of any kind incurred as a result of Your use of any content posted, emailed, transmitted, or otherwise made available via the Service.
+
+The Company shall not be liable for any loss or damage resulting from failure to meet any of Your expectations related to the use or performance of the Service, including but not limited to inaccuracies in GPS location services, suggested itineraries, or other location-based services.
+
+Some jurisdictions do not allow the exclusion or limitation of certain types of liability, such as incidental or consequential damages or implied warranties. Therefore, the above limitations or exclusions may not apply to You. In such jurisdictions, each party's liability will be limited to the greatest extent permitted by law.
+
+To the extent permitted by applicable law, the Company and its suppliers’ aggregate liability to You for any claims arising from or related to the use of the Service shall in no event exceed the greater of (a) the amount You paid, if any, for accessing the Service during the twelve (12) month period preceding the claim or (b) one hundred (100) USD.
+
+You agree that the limitations of liability set forth in this section will survive any termination or expiration of these Terms and apply even if any limited remedy specified in these Terms is found to have failed its essential purpose.
+"AS IS" and "AS AVAILABLE" Disclaimer
+
+The Service is provided to You "AS IS" and "AS AVAILABLE" and with all faults and defects without warranty of any kind. To the maximum extent permitted under applicable law, the Company, on its own behalf and on behalf of its Affiliates and its and their respective licensors and service providers, expressly disclaims all warranties, whether express, implied, statutory or otherwise, with respect to the Service, including all implied warranties of merchantability, fitness for a particular purpose, title and non-infringement, and warranties that may arise out of course of dealing, course of performance, usage or trade practice. Without limitation to the foregoing, the Company provides no warranty or undertaking, and makes no representation of any kind that the Service will meet Your requirements, achieve any intended results, be compatible or work with any other software, applications, systems or services, operate without interruption, meet any performance or reliability standards or be error free or that any errors or defects can or will be corrected.
+
+Without limiting the foregoing, neither the Company nor any of the company's provider makes any representation or warranty of any kind, express or implied: (i) as to the operation or availability of the Service, or the information, content, and materials or products included thereon; (ii) that the Service will be uninterrupted or error-free; (iii) as to the accuracy, reliability, or currency of any information or content provided through the Service; or (iv) that the Service, its servers, the content, or e-mails sent from or on behalf of the Company are free of viruses, scripts, trojan horses, worms, malware, timebombs or other harmful components.
+
+Some jurisdictions do not allow the exclusion of certain types of warranties or limitations on applicable statutory rights of a consumer, so some or all of the above exclusions and limitations may not apply to You. But in such a case the exclusions and limitations set forth in this section shall be applied to the greatest extent enforceable under applicable law.
+
+
+## Governing Law
+
+The laws of the Country, excluding its conflicts of law rules, shall govern this Terms and Your use of the Service. Your use of the Application may also be subject to other local, state, national, or international laws.
+
+
+## Disputes Resolution
+
+If You have any concern or dispute about the Service, You agree to first try to resolve the dispute informally by contacting the Company.
+For European Union (EU) Users
+
+If You are a European Union consumer, you will benefit from any mandatory provisions of the law of the country in which You are resident.
+
+
+## United States Legal Compliance
+
+You represent and warrant that (i) You are not located in a country that is subject to the United States government embargo, or that has been designated by the United States government as a "terrorist supporting" country, and (ii) You are not listed on any United States government list of prohibited or restricted parties.
+
+
+## Severability and Waiver
+### Severability
+
+If any provision of these Terms is held to be unenforceable or invalid, such provision will be changed and interpreted to accomplish the objectives of such provision to the greatest extent possible under applicable law and the remaining provisions will continue in full force and effect.
+
+### Waiver
+
+Except as provided herein, the failure to exercise a right or to require performance of an obligation under these Terms shall not affect a party's ability to exercise such right or require such performance at any time thereafter nor shall the waiver of a breach constitute a waiver of any subsequent breach.
+Translation Interpretation
+
+These Terms and Conditions may have been translated if We have made them available to You on our Service. You agree that the original English text shall prevail in the case of a dispute.
+Changes to These Terms and Conditions
+
+We reserve the right, at Our sole discretion, to modify or replace these Terms at any time. If a revision is material We will make reasonable efforts to provide at least 30 days' notice prior to any new terms taking effect. What constitutes a material change will be determined at Our sole discretion.
+
+By continuing to access or use Our Service after those revisions become effective, You agree to be bound by the revised terms. If You do not agree to the new terms, in whole or in part, please stop using the website and the Service.+
+
+## Contact Us
+
+If you have any questions about these Terms and Conditions, You can contact us:
+  - By visiting this page on our website: https://anydev.info
diff --git a/frontend/ios/fastlane/Fastfile b/frontend/ios/fastlane/Fastfile
index f3e23f4..b5e15f1 100644
--- a/frontend/ios/fastlane/Fastfile
+++ b/frontend/ios/fastlane/Fastfile
@@ -71,7 +71,6 @@ platform :ios do
       "",
       "s/IOS_GOOGLE_MAPS_API_KEY/#{ENV["IOS_GOOGLE_MAPS_API_KEY"]}/g",
       "../Runner/AppDelegate.swift"
-
     )
 
     sh(
@@ -93,7 +92,7 @@ platform :ios do
       skip_screenshots: true,
       skip_metadata: true,
       precheck_include_in_app_purchases: false,
-      
+
       submit_for_review: true,
       automatic_release: true,
       # automatically release the app after review
diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart
index ed4121f..2fe5991 100644
--- a/frontend/lib/main.dart
+++ b/frontend/lib/main.dart
@@ -16,7 +16,6 @@ final SavedTrips savedTrips = SavedTrips();
 class App extends StatelessWidget {
   const App({super.key});
 
-
   @override
   Widget build(BuildContext context) => MaterialApp(
     title: APP_NAME,
diff --git a/frontend/lib/modules/landmark_card.dart b/frontend/lib/modules/landmark_card.dart
index 8579219..491b6da 100644
--- a/frontend/lib/modules/landmark_card.dart
+++ b/frontend/lib/modules/landmark_card.dart
@@ -69,7 +69,6 @@ class _LandmarkCardState extends State<LandmarkCard> {
                           padding: EdgeInsets.all(5),
                           child: Row(
                             mainAxisAlignment: MainAxisAlignment.center,
-                            spacing: 5,
                             children: [
                               Icon(Icons.timer_outlined, size: 16),
                               Text("${widget.landmark.duration?.inMinutes} minutes"),
diff --git a/frontend/lib/modules/onbarding_agreement_card.dart b/frontend/lib/modules/onbarding_agreement_card.dart
new file mode 100644
index 0000000..8f3d540
--- /dev/null
+++ b/frontend/lib/modules/onbarding_agreement_card.dart
@@ -0,0 +1,97 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_markdown/flutter_markdown.dart';
+
+import 'package:anyway/modules/onboarding_card.dart';
+
+
+class OnboardingAgreementCard extends StatefulWidget {
+  final String title;
+  final String description;
+  final String imagePath;
+  final String agreementTextPath;
+  final ValueChanged<bool> onAgreementChanged;
+
+
+  OnboardingAgreementCard({
+    super.key, 
+    required this.title,
+    required this.description,
+    required this.imagePath,
+    required this.agreementTextPath,
+    required this.onAgreementChanged
+  });
+
+  @override
+  State<OnboardingAgreementCard> createState() => _OnboardingAgreementCardState();
+}
+
+class _OnboardingAgreementCardState extends State<OnboardingAgreementCard> {
+  bool agreed = false;
+  @override
+  Widget build(BuildContext context) {
+    return Padding(
+      padding: EdgeInsets.all(20),
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: [
+          OnboardingCard(title: widget.title, description: widget.description, imagePath: widget.imagePath),
+          Padding(padding: EdgeInsets.only(top: 20)),
+          Row(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              Checkbox(
+                value: agreed,
+                onChanged: (value) {
+                  setState(() {
+                    agreed = value!;
+                    widget.onAgreementChanged(value);
+                  });
+                },
+              ),
+              Text(
+                "I agree to the ",
+                style: Theme.of(context).textTheme.bodyMedium!.copyWith(
+                  color: Colors.white,
+                ),
+              ),
+              GestureDetector(
+                onTap: () {
+                  // show a dialog with the agreement text
+                  showDialog(
+                    context: context,
+                    builder: (BuildContext context) {
+                      return AlertDialog(
+                        scrollable: true,
+                        content: FutureBuilder(
+                          future: DefaultAssetBundle.of(context).loadString(widget.agreementTextPath),
+                          builder: (context, snapshot) {
+                            if (snapshot.hasData) {
+                              return MarkdownBody(
+                                data: snapshot.data.toString(),
+                              );
+                            } else {
+                              return CircularProgressIndicator();
+                            }
+                            
+                          },
+                        )
+                      );
+                    }
+                  );
+
+                },
+                child: Text(
+                  "Terms of Service (click to view)",
+                  style: Theme.of(context).textTheme.bodyMedium!.copyWith(
+                    color: Colors.white,
+                    fontWeight: FontWeight.bold,
+                  ),
+                ),
+              ),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/frontend/lib/modules/onboarding_card.dart b/frontend/lib/modules/onboarding_card.dart
index 05fc340..094d641 100644
--- a/frontend/lib/modules/onboarding_card.dart
+++ b/frontend/lib/modules/onboarding_card.dart
@@ -22,9 +22,7 @@ class OnboardingCard extends StatelessWidget {
         children: [
           Text(
             title,
-            style: TextStyle(
-              fontSize: 24,
-              fontWeight: FontWeight.bold,
+            style: Theme.of(context).textTheme.headlineLarge!.copyWith(
               color: Colors.white,
             ),
           ),
@@ -36,13 +34,12 @@ class OnboardingCard extends StatelessWidget {
           Padding(padding: EdgeInsets.only(top: 20)),
           Text(
             description,
-            style: TextStyle(
-              fontSize: 16,
+            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
+              color: Colors.white,
             ),
           ),
-
         ]
       ),
     );
   }
-}
\ No newline at end of file
+}
diff --git a/frontend/lib/pages/onboarding.dart b/frontend/lib/pages/onboarding.dart
index 3692cb8..2de42b6 100644
--- a/frontend/lib/pages/onboarding.dart
+++ b/frontend/lib/pages/onboarding.dart
@@ -1,33 +1,37 @@
 import 'dart:ui';
 
 import 'package:anyway/constants.dart';
+import 'package:anyway/modules/onbarding_agreement_card.dart';
 import 'package:anyway/modules/onboarding_card.dart';
 import 'package:anyway/pages/new_trip_location.dart';
 import 'package:flutter/material.dart';
+import 'package:shared_preferences/shared_preferences.dart';
 
-const List<Widget> onboardingCards = [
-  OnboardingCard(
+
+List<Widget> onboardingCards = [
+  const OnboardingCard(
     title: "Welcome to anyway!",
     description: "Anyway helps you plan a city trip that suits your wishes.",
-    imagePath: "assets/city.svg"
+    imagePath: "assets/cld-server.svg"
   ),
-  OnboardingCard(
-    title: "Find your way",
+  const OnboardingCard(
+    title: "Do your thing",
     description: "Bored by churches? No problem! Hate shopping? No worries! Instead of suggesting the generic trips that bore you, anyway will try to give you recommendations that really suit you.",
-    imagePath: "assets/plan.svg"
+    imagePath: "assets/con-drill.svg"
   ),
-  OnboardingCard(
+  const OnboardingCard(
     title: "Change your mind",
     description: "Feet get sore, the weather changes. Anyway understands that! Move or remove destinations, visit hidden gems along your journey, do your own thing. Anyway adapts to your spontaneous decisions.",
-    imagePath: "assets/cat.svg"
+    imagePath: "assets/cel-snow-globe.svg"
   ),
-  OnboardingCard(
+  const OnboardingCard(
     title: "Feeling lost?",
     description: "Whenever you are confused or need help with the app, look out for the question mark in the top right corner. Help is just a tap away!",
-    imagePath: "assets/confused.svg"
+    imagePath: "assets/gen-lifebelt.svg"
   ),
 ];
 
+
 class OnboardingPage extends StatefulWidget {
   const OnboardingPage({super.key});
 
@@ -37,9 +41,24 @@ class OnboardingPage extends StatefulWidget {
 
 class _OnboardingPageState extends State<OnboardingPage> {
   final PageController _controller = PageController();
+  late List<Widget> fullCards;
+
+
 
   @override
   Widget build(BuildContext context) {
+
+    Widget agreementCard = OnboardingAgreementCard(
+      title: "The annoying stuff",
+      description: "By using anyway, you agree to our terms and conditions and privacy policy. We don't use cookies or tracking, we don't store the data you submit. We are not responsible for any damage or loss caused by using anyway.",
+      imagePath: "assets/con-warning.svg",
+      agreementTextPath: "assets/terms_and_conditions.md",
+      onAgreementChanged: onAgreementChanged,
+    );
+    // need to add the agreement from within the function because it needs to be able to call setState
+    fullCards = onboardingCards + [agreementCard];
+
+
     return Scaffold(
       body: Stack(
         children: [
@@ -55,8 +74,8 @@ class _OnboardingPageState extends State<OnboardingPage> {
                         end: Alignment.bottomRight,
                         colors: APP_GRADIENT.colors,
                         stops: [
-                          (_controller.hasClients ? _controller.page ?? _controller.initialPage : _controller.initialPage) / onboardingCards.length,
-                          (_controller.hasClients ? _controller.page ?? _controller.initialPage + 1 : _controller.initialPage + 1) / onboardingCards.length,
+                          (_controller.hasClients ? (_controller.page ?? _controller.initialPage) : _controller.initialPage) / onboardingCards.length,
+                          (_controller.hasClients ? (_controller.page ?? _controller.initialPage) + 1 : _controller.initialPage + 1) / onboardingCards.length,
                         ],
                       ),
                     ),
@@ -64,7 +83,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
                   BackdropFilter(
                     filter: ImageFilter.blur(sigmaX: 100, sigmaY: 100),
                     child: Container(
-                      color: Colors.black.withOpacity(0),
+                      color: Colors.black.withValues(alpha: 0.2)
                     ),
                   ),
                 ],
@@ -74,46 +93,73 @@ class _OnboardingPageState extends State<OnboardingPage> {
           PageView(
             controller: _controller,
             children: List.generate(
-              onboardingCards.length,
+              fullCards.length,
               (index) {
                 return Container(
                   alignment: Alignment.center,
-                  child: onboardingCards[index],
+                  child: fullCards[index],
                 );
               }
             ),
           ),
         ],
       ),
-      floatingActionButton: FloatingActionButton.extended(
-        onPressed: () {
-          if (_controller.page == onboardingCards.length - 1) {
-            Navigator.of(context).push(
-              MaterialPageRoute(
-                builder: (context) => const NewTripPage()
-              )
-            );
-          } else {
-            _controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
-          }
-        },
-        label: AnimatedBuilder(
-          animation: _controller,
-          builder: (context, child) {
-            if ((_controller.page ?? _controller.initialPage) == onboardingCards.length - 1) {
-              return Row(
-                children: [
-                  const Text("Start planning!"),
-                  Padding(padding: const EdgeInsets.only(right: 8.0)),
-                  const Icon(Icons.map_outlined)
-                ],
-              );
-            } else {
-              return const Icon(Icons.arrow_forward);
-            }
-          }
-        )
-      ),
+
+      floatingActionButton: nextButton(_controller)
     );
   }
-}
\ No newline at end of file
+
+  Widget nextButton(PageController controller) => AnimatedBuilder(
+    animation: _controller,
+    builder: (context, child) {
+      if ((_controller.hasClients ? (_controller.page ?? _controller.initialPage) : 0) != fullCards.length - 1) {
+        return FloatingActionButton.extended(
+          onPressed: () {
+            controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
+          },
+          label: Icon(Icons.arrow_forward)
+        );
+      } else {
+        // only allow the user to proceed if they have agreed to the terms and conditions
+        Future<bool> hasAgreed = SharedPreferences.getInstance().then(
+          (SharedPreferences prefs) {
+            return prefs.getBool('TC_agree') ?? false;
+          }
+        );
+
+        return FutureBuilder(
+          future: hasAgreed,
+          builder: (context, snapshot){
+            if (snapshot.hasData && snapshot.data!) {
+              return FloatingActionButton.extended(
+                onPressed: () {
+                  Navigator.of(context).push(
+                    MaterialPageRoute(
+                      builder: (context) => const NewTripPage()
+                    )
+                  );
+                },
+                label: const Row(
+                  children: [
+                    Text("Start planning!"),
+                    Padding(padding: EdgeInsets.only(right: 8.0)),
+                    Icon(Icons.map_outlined)
+                  ],
+                )
+              );
+            } else {
+              return Container();
+            }
+          }
+        );
+      }
+    }
+  );
+
+  void onAgreementChanged(bool value) async {
+    SharedPreferences prefs = await SharedPreferences.getInstance();
+    await prefs.setBool('TC_agree', value);
+    // Update the state of the OnboardingPage
+    setState(() {});
+  }
+}
diff --git a/frontend/lib/pages/settings.dart b/frontend/lib/pages/settings.dart
index b5d3240..c2e71d2 100644
--- a/frontend/lib/pages/settings.dart
+++ b/frontend/lib/pages/settings.dart
@@ -1,11 +1,12 @@
-import 'package:anyway/constants.dart';
-import 'package:anyway/layouts/scaffold.dart';
-import 'package:anyway/main.dart';
 import 'package:flutter/material.dart';
 import 'package:permission_handler/permission_handler.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'package:url_launcher/url_launcher.dart';
 
+import 'package:anyway/main.dart';
+import 'package:anyway/constants.dart';
+import 'package:anyway/layouts/scaffold.dart';
+
 
 bool debugMode = false;
 
diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock
index bb2aad4..a79e921 100644
--- a/frontend/pubspec.lock
+++ b/frontend/pubspec.lock
@@ -21,10 +21,10 @@ packages:
     dependency: transitive
     description:
       name: async
-      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+      sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
       url: "https://pub.dev"
     source: hosted
-    version: "2.11.0"
+    version: "2.12.0"
   auto_size_text:
     dependency: "direct main"
     description:
@@ -37,10 +37,10 @@ packages:
     dependency: transitive
     description:
       name: boolean_selector
-      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.1"
+    version: "2.1.2"
   cached_network_image:
     dependency: "direct main"
     description:
@@ -69,10 +69,10 @@ packages:
     dependency: transitive
     description:
       name: characters
-      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+      sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.0"
+    version: "1.4.0"
   checked_yaml:
     dependency: transitive
     description:
@@ -93,18 +93,18 @@ packages:
     dependency: transitive
     description:
       name: clock
-      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
       url: "https://pub.dev"
     source: hosted
-    version: "1.1.1"
+    version: "1.1.2"
   collection:
     dependency: transitive
     description:
       name: collection
-      sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
+      sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
       url: "https://pub.dev"
     source: hosted
-    version: "1.19.0"
+    version: "1.19.1"
   crypto:
     dependency: transitive
     description:
@@ -149,10 +149,10 @@ packages:
     dependency: transitive
     description:
       name: fake_async
-      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+      sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.1"
+    version: "1.3.2"
   ffi:
     dependency: transitive
     description:
@@ -206,6 +206,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.0.0"
+  flutter_markdown:
+    dependency: "direct main"
+    description:
+      name: flutter_markdown
+      sha256: e7bbc718adc9476aa14cfddc1ef048d2e21e4e8f18311aaac723266db9f9e7b5
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.7.6+2"
   flutter_plugin_android_lifecycle:
     dependency: transitive
     description:
@@ -412,18 +420,18 @@ packages:
     dependency: transitive
     description:
       name: leak_tracker
-      sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
+      sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
       url: "https://pub.dev"
     source: hosted
-    version: "10.0.7"
+    version: "10.0.8"
   leak_tracker_flutter_testing:
     dependency: transitive
     description:
       name: leak_tracker_flutter_testing
-      sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
+      sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.8"
+    version: "3.0.9"
   leak_tracker_testing:
     dependency: transitive
     description:
@@ -448,14 +456,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.5.0"
+  markdown:
+    dependency: transitive
+    description:
+      name: markdown
+      sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.3.0"
   matcher:
     dependency: transitive
     description:
       name: matcher
-      sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
+      sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
       url: "https://pub.dev"
     source: hosted
-    version: "0.12.16+1"
+    version: "0.12.17"
   material_color_utilities:
     dependency: transitive
     description:
@@ -468,10 +484,10 @@ packages:
     dependency: transitive
     description:
       name: meta
-      sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
+      sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
       url: "https://pub.dev"
     source: hosted
-    version: "1.15.0"
+    version: "1.16.0"
   nested:
     dependency: transitive
     description:
@@ -492,10 +508,10 @@ packages:
     dependency: transitive
     description:
       name: path
-      sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+      sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
       url: "https://pub.dev"
     source: hosted
-    version: "1.9.0"
+    version: "1.9.1"
   path_parsing:
     dependency: transitive
     description:
@@ -721,10 +737,10 @@ packages:
     dependency: transitive
     description:
       name: source_span
-      sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+      sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
       url: "https://pub.dev"
     source: hosted
-    version: "1.10.0"
+    version: "1.10.1"
   sprintf:
     dependency: transitive
     description:
@@ -753,18 +769,18 @@ packages:
     dependency: transitive
     description:
       name: stack_trace
-      sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
+      sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
       url: "https://pub.dev"
     source: hosted
-    version: "1.12.0"
+    version: "1.12.1"
   stream_channel:
     dependency: transitive
     description:
       name: stream_channel
-      sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
+      sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.2"
+    version: "2.1.4"
   stream_transform:
     dependency: transitive
     description:
@@ -777,10 +793,10 @@ packages:
     dependency: transitive
     description:
       name: string_scanner
-      sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
+      sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.0"
+    version: "1.4.1"
   synchronized:
     dependency: transitive
     description:
@@ -793,18 +809,18 @@ packages:
     dependency: transitive
     description:
       name: term_glyph
-      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
       url: "https://pub.dev"
     source: hosted
-    version: "1.2.1"
+    version: "1.2.2"
   test_api:
     dependency: transitive
     description:
       name: test_api
-      sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
+      sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
       url: "https://pub.dev"
     source: hosted
-    version: "0.7.3"
+    version: "0.7.4"
   typed_data:
     dependency: transitive
     description:
@@ -921,10 +937,10 @@ packages:
     dependency: transitive
     description:
       name: vm_service
-      sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
+      sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
       url: "https://pub.dev"
     source: hosted
-    version: "14.3.0"
+    version: "14.3.1"
   web:
     dependency: transitive
     description:
@@ -966,5 +982,5 @@ packages:
     source: hosted
     version: "3.1.2"
 sdks:
-  dart: ">=3.5.0 <4.0.0"
+  dart: ">=3.7.0-0 <4.0.0"
   flutter: ">=3.24.0"
diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml
index 458a132..ea783ef 100644
--- a/frontend/pubspec.yaml
+++ b/frontend/pubspec.yaml
@@ -52,6 +52,7 @@ dependencies:
   permission_handler: ^11.3.1
   geolocator: ^13.0.1
   fuzzywuzzy: ^1.2.0
+  flutter_markdown: ^0.7.6+2
 
 dev_dependencies:
   flutter_test:
-- 
2.47.2


From e148c851e11e07c78f71e4bf13319d48fc466813 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sun, 23 Mar 2025 20:00:24 +0100
Subject: [PATCH 6/7] quite a few UX improvements

---
 .../current_trip_loading_indicator.dart       |  3 +-
 .../lib/modules/current_trip_summary.dart     | 13 ++--
 frontend/lib/modules/new_trip_map.dart        |  1 +
 .../lib/modules/onbarding_agreement_card.dart | 37 +++++++---
 .../lib/modules/step_between_landmarks.dart   |  2 +-
 frontend/lib/pages/new_trip_preferences.dart  |  9 +++
 frontend/lib/pages/no_trips_page.dart         | 50 ++++++++++++++
 frontend/lib/pages/onboarding.dart            | 10 +--
 frontend/lib/structs/agreement.dart           | 17 +++++
 frontend/lib/structs/trip.dart                | 13 ++--
 frontend/lib/utils/get_first_page.dart        | 68 ++++++++++---------
 frontend/lib/utils/load_trips.dart            |  3 +-
 12 files changed, 166 insertions(+), 60 deletions(-)
 create mode 100644 frontend/lib/pages/no_trips_page.dart
 create mode 100644 frontend/lib/structs/agreement.dart

diff --git a/frontend/lib/modules/current_trip_loading_indicator.dart b/frontend/lib/modules/current_trip_loading_indicator.dart
index 83a216a..60cc98c 100644
--- a/frontend/lib/modules/current_trip_loading_indicator.dart
+++ b/frontend/lib/modules/current_trip_loading_indicator.dart
@@ -140,9 +140,10 @@ class _AnimatedDotsTextState extends State<AnimatedDotsText> {
   @override
   Widget build(BuildContext context) {
     String dots = '.' * dotCount;
-    return Text(
+    return AutoSizeText(
       '${widget.baseText}$dots',
       style: widget.style,
+      maxLines: 2,
     );
   }
 }
diff --git a/frontend/lib/modules/current_trip_summary.dart b/frontend/lib/modules/current_trip_summary.dart
index e7aa4a5..b7c5654 100644
--- a/frontend/lib/modules/current_trip_summary.dart
+++ b/frontend/lib/modules/current_trip_summary.dart
@@ -15,8 +15,9 @@ class CurrentTripSummary extends StatefulWidget {
 
 class _CurrentTripSummaryState extends State<CurrentTripSummary> {
   @override
-  Widget build(BuildContext context) {
-    return Padding(
+  Widget build(BuildContext context) => ListenableBuilder(
+    listenable: widget.trip,
+    builder: (context, child) => Padding(
       padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
       child: Row(
         mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -25,18 +26,18 @@ class _CurrentTripSummaryState extends State<CurrentTripSummary> {
             children: [
               const Icon(Icons.flag, size: 20),
               const Padding(padding: EdgeInsets.only(right: 10)),
-              Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge),
+              Text('${widget.trip.landmarks.length} stops', style: Theme.of(context).textTheme.bodyLarge),
             ]
           ),
           Row(
             children: [
               const Icon(Icons.hourglass_bottom_rounded, size: 20),
               const Padding(padding: EdgeInsets.only(right: 10)),
-              Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge),
+              Text('${widget.trip.totalTime.inHours}h ${widget.trip.totalTime.inMinutes.remainder(60)}min', style: Theme.of(context).textTheme.bodyLarge),
             ]
           ),
         ],
       )
-    );
-  }
+    )
+  );
 }
diff --git a/frontend/lib/modules/new_trip_map.dart b/frontend/lib/modules/new_trip_map.dart
index e4e5400..b033b16 100644
--- a/frontend/lib/modules/new_trip_map.dart
+++ b/frontend/lib/modules/new_trip_map.dart
@@ -78,6 +78,7 @@ class _NewTripMapState extends State<NewTripMap> {
     widget.trip.addListener(updateTripDetails);
     Future<SharedPreferences> preferences = SharedPreferences.getInstance();
 
+
     return FutureBuilder(
       future: preferences,
       builder: (context, snapshot) {
diff --git a/frontend/lib/modules/onbarding_agreement_card.dart b/frontend/lib/modules/onbarding_agreement_card.dart
index 8f3d540..bc7a293 100644
--- a/frontend/lib/modules/onbarding_agreement_card.dart
+++ b/frontend/lib/modules/onbarding_agreement_card.dart
@@ -1,3 +1,4 @@
+import 'package:anyway/structs/agreement.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_markdown/flutter_markdown.dart';
 
@@ -26,7 +27,6 @@ class OnboardingAgreementCard extends StatefulWidget {
 }
 
 class _OnboardingAgreementCardState extends State<OnboardingAgreementCard> {
-  bool agreed = false;
   @override
   Widget build(BuildContext context) {
     return Padding(
@@ -39,21 +39,42 @@ class _OnboardingAgreementCardState extends State<OnboardingAgreementCard> {
           Row(
             mainAxisAlignment: MainAxisAlignment.center,
             children: [
-              Checkbox(
-                value: agreed,
-                onChanged: (value) {
-                  setState(() {
-                    agreed = value!;
-                    widget.onAgreementChanged(value);
-                  });
+              // The checkbox of the agreement
+              FutureBuilder(
+                future: getAgreement(),
+                builder: (context, snapshot) {
+                  bool agreed = false;
+                  if (snapshot.connectionState == ConnectionState.done) {
+                    if (snapshot.hasData) {
+                      Agreement agreement = snapshot.data!;
+                      agreed = agreement.agreed;
+                    } else {
+                      agreed = false;
+                    }
+                  } else {
+                    agreed = false;
+                  }
+                  return Checkbox(
+                    value: agreed,
+                    onChanged: (value) {
+                      setState(() {
+                        widget.onAgreementChanged(value!);
+                      });
+                      saveAgreement(value!);
+                    },
+                  );
                 },
               ),
+              
+              // The text of the agreement
               Text(
                 "I agree to the ",
                 style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                   color: Colors.white,
                 ),
               ),
+              
+              // The clickable text of the agreement that shows the agreement text
               GestureDetector(
                 onTap: () {
                   // show a dialog with the agreement text
diff --git a/frontend/lib/modules/step_between_landmarks.dart b/frontend/lib/modules/step_between_landmarks.dart
index 129763f..6dbcf4b 100644
--- a/frontend/lib/modules/step_between_landmarks.dart
+++ b/frontend/lib/modules/step_between_landmarks.dart
@@ -48,7 +48,7 @@ class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
             children: [
               const Icon(Icons.directions_walk),
               Text(
-                time == null ? "" : "About $time min",
+                time == null ? "" : "$time min",
                 style: const TextStyle(fontSize: 10)
               ),
             ],
diff --git a/frontend/lib/pages/new_trip_preferences.dart b/frontend/lib/pages/new_trip_preferences.dart
index 76aaf10..ab6146a 100644
--- a/frontend/lib/pages/new_trip_preferences.dart
+++ b/frontend/lib/pages/new_trip_preferences.dart
@@ -1,5 +1,6 @@
 import 'package:anyway/layouts/scaffold.dart';
 import 'package:anyway/modules/new_trip_button.dart';
+import 'package:anyway/structs/landmark.dart';
 import 'package:anyway/structs/preferences.dart';
 import 'package:anyway/structs/trip.dart';
 import 'package:flutter/cupertino.dart';
@@ -20,6 +21,14 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> with Sc
 
   @override
   Widget build(BuildContext context) {
+    // Ensure that the trip is "empty" save for the start landmark
+    // This is necessary because users can swipe back to this page even after the trip has been created
+    if (widget.trip.landmarks.length > 1) {
+      Landmark start = widget.trip.landmarks.first;
+      widget.trip.landmarks.clear();
+      widget.trip.addLandmark(start);
+    }
+
     return mainScaffold(
       context,
       child: Scaffold(
diff --git a/frontend/lib/pages/no_trips_page.dart b/frontend/lib/pages/no_trips_page.dart
new file mode 100644
index 0000000..9c46525
--- /dev/null
+++ b/frontend/lib/pages/no_trips_page.dart
@@ -0,0 +1,50 @@
+import 'package:anyway/pages/new_trip_location.dart';
+import 'package:flutter/material.dart';
+
+import 'package:anyway/layouts/scaffold.dart';
+class NoTripsPage extends StatefulWidget {
+  const NoTripsPage({super.key});
+
+  @override
+  State<NoTripsPage> createState() => _NoTripsPageState();
+}
+
+class _NoTripsPageState extends State<NoTripsPage> with ScaffoldLayout {
+  @override
+  Widget build(BuildContext context) => mainScaffold(
+    context,
+    child: Scaffold(
+      body: Center(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Text(
+              "No trips yet",
+              style: Theme.of(context).textTheme.headlineMedium,
+            ),
+            Text(
+              "You can start a new trip by clicking the button below",
+              style: Theme.of(context).textTheme.bodyMedium,
+            ),
+          ],
+        ),
+      ),
+      floatingActionButton: FloatingActionButton.extended(
+        onPressed: () {
+          Navigator.of(context).push(
+            MaterialPageRoute(
+              builder: (context) => const NewTripPage()
+            )
+          );
+        },
+        label: const Row(
+          children: [
+            Text("Start planning!"),
+            Padding(padding: EdgeInsets.only(right: 8.0)),
+            Icon(Icons.map_outlined)
+          ],
+        )
+      )
+    )
+  );
+}
\ No newline at end of file
diff --git a/frontend/lib/pages/onboarding.dart b/frontend/lib/pages/onboarding.dart
index 2de42b6..847ee3a 100644
--- a/frontend/lib/pages/onboarding.dart
+++ b/frontend/lib/pages/onboarding.dart
@@ -4,6 +4,7 @@ import 'package:anyway/constants.dart';
 import 'package:anyway/modules/onbarding_agreement_card.dart';
 import 'package:anyway/modules/onboarding_card.dart';
 import 'package:anyway/pages/new_trip_location.dart';
+import 'package:anyway/structs/agreement.dart';
 import 'package:flutter/material.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 
@@ -121,11 +122,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
         );
       } else {
         // only allow the user to proceed if they have agreed to the terms and conditions
-        Future<bool> hasAgreed = SharedPreferences.getInstance().then(
-          (SharedPreferences prefs) {
-            return prefs.getBool('TC_agree') ?? false;
-          }
-        );
+        Future<bool> hasAgreed = getAgreement().then((agreement) => agreement.agreed);
 
         return FutureBuilder(
           future: hasAgreed,
@@ -157,8 +154,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
   );
 
   void onAgreementChanged(bool value) async {
-    SharedPreferences prefs = await SharedPreferences.getInstance();
-    await prefs.setBool('TC_agree', value);
+    saveAgreement(value);
     // Update the state of the OnboardingPage
     setState(() {});
   }
diff --git a/frontend/lib/structs/agreement.dart b/frontend/lib/structs/agreement.dart
new file mode 100644
index 0000000..321ca74
--- /dev/null
+++ b/frontend/lib/structs/agreement.dart
@@ -0,0 +1,17 @@
+import 'package:shared_preferences/shared_preferences.dart';
+
+final class Agreement{
+  bool agreed;
+
+  Agreement({required this.agreed});
+}
+
+void saveAgreement(bool agreed) async {
+  SharedPreferences prefs = await SharedPreferences.getInstance();
+  prefs.setBool('agreed_to_terms_and_conditions', agreed);
+}
+
+Future<Agreement> getAgreement() async {
+  SharedPreferences prefs = await SharedPreferences.getInstance();
+  return Agreement(agreed: prefs.getBool('agreed_to_terms_and_conditions') ?? false);
+}
diff --git a/frontend/lib/structs/trip.dart b/frontend/lib/structs/trip.dart
index 820749e..ef09e4e 100644
--- a/frontend/lib/structs/trip.dart
+++ b/frontend/lib/structs/trip.dart
@@ -12,7 +12,7 @@ import 'package:shared_preferences/shared_preferences.dart';
 
 class Trip with ChangeNotifier {
   String uuid;
-  int totalTime;
+  Duration totalTime;
   LinkedList<Landmark> landmarks;
   // could be empty as well
   String? errorDescription;
@@ -44,7 +44,7 @@ class Trip with ChangeNotifier {
 
   Trip({
     this.uuid = 'pending',
-    this.totalTime = 0,
+    this.totalTime = Duration.zero,
     LinkedList<Landmark>? landmarks
     // a trip can be created with no landmarks, but the list should be initialized anyway
   }) : landmarks = landmarks ?? LinkedList<Landmark>();
@@ -53,7 +53,7 @@ class Trip with ChangeNotifier {
   factory Trip.fromJson(Map<String, dynamic> json) {
     Trip trip = Trip(
       uuid: json['uuid'],
-      totalTime: json['total_time'],
+      totalTime: Duration(minutes: json['total_time']),
     );
 
     return trip;
@@ -61,7 +61,7 @@ class Trip with ChangeNotifier {
 
   void loadFromJson(Map<String, dynamic> json) {
     uuid = json['uuid'];
-    totalTime = json['total_time'];
+    totalTime = Duration(minutes: json['total_time']);
     notifyListeners();
   }
 
@@ -82,9 +82,12 @@ class Trip with ChangeNotifier {
     // removing the landmark means we need to recompute the time between the two adjoined landmarks
     if (previous != null && next != null) {
       // previous.next = next happens automatically since we are using a LinkedList
+      this.totalTime -= previous.tripTime ?? Duration.zero;
       previous.tripTime = null;
       // TODO
     }
+    this.totalTime -= landmark.tripTime ?? Duration.zero;
+
     notifyListeners();
   }
 
@@ -111,7 +114,7 @@ class Trip with ChangeNotifier {
 
   Map<String, dynamic> toJson() => {
     'uuid': uuid,
-    'total_time': totalTime,
+    'total_time': totalTime.inMinutes,
     'first_landmark_uuid': landmarks.first.uuid
   };
 
diff --git a/frontend/lib/utils/get_first_page.dart b/frontend/lib/utils/get_first_page.dart
index 26f2787..bc54b79 100644
--- a/frontend/lib/utils/get_first_page.dart
+++ b/frontend/lib/utils/get_first_page.dart
@@ -1,44 +1,50 @@
 import 'package:anyway/main.dart';
+import 'package:anyway/pages/no_trips_page.dart';
+import 'package:anyway/structs/agreement.dart';
 import 'package:flutter/material.dart';
 
 import 'package:anyway/structs/trip.dart';
-import 'package:anyway/utils/load_trips.dart';
 import 'package:anyway/pages/current_trip.dart';
 import 'package:anyway/pages/onboarding.dart';
 
 
 Widget getFirstPage() {
-  SavedTrips trips = savedTrips;
-  trips.loadTrips();
-
-  return ListenableBuilder(
-    listenable: trips,
-    builder: (BuildContext context, Widget? child) {
-      List<Trip> items = trips.trips;
-      if (items.isNotEmpty) {
-        return TripPage(trip: items[0]);
+  // check if the user has already seen the onboarding and agreed to the terms of service
+  return FutureBuilder(
+    future: getAgreement(),
+    builder: (context, snapshot) {
+      if (snapshot.connectionState == ConnectionState.done) {
+        if (snapshot.hasData) {
+          Agreement agrement = snapshot.data!;
+          if (agrement.agreed) {
+            return FutureBuilder(
+              future: savedTrips.loadTrips(),
+              builder: (context, snapshot) {
+                if (snapshot.connectionState == ConnectionState.done) {
+                  if (snapshot.hasData) {
+                    List<Trip> trips = snapshot.data!;
+                    if (trips.length > 0) {
+                      return TripPage(trip: trips[0]);
+                    } else {
+                      return NoTripsPage();
+                    }
+                  } else {
+                    return Center(child: CircularProgressIndicator());
+                  }
+                } else {
+                  return Center(child: CircularProgressIndicator());
+                }
+              },
+            );
+          } else {
+            return OnboardingPage();
+          }
+        } else {
+          return OnboardingPage();
+        }
       } else {
-        return const OnboardingPage();
+        return OnboardingPage();
       }
-    }
+    },
   );
-  // Future<List<Trip>> trips = loadTrips();
-  // // test if there are any active trips
-  // // if there are, return the trip list
-  // // if there are not, return the onboarding page
-  // return FutureBuilder(
-  //   future: trips,
-  //   builder: (context, snapshot) {
-  //     if (snapshot.hasData) {
-  //       List<Trip> availableTrips = snapshot.data!;
-  //       if (availableTrips.isNotEmpty) {
-  //         return TripPage(trip: availableTrips[0]);
-  //       } else {
-  //         return OnboardingPage();
-  //       }
-  //     } else {
-  //       return CircularProgressIndicator();
-  //     }
-  //   }
-  // );
 }
\ No newline at end of file
diff --git a/frontend/lib/utils/load_trips.dart b/frontend/lib/utils/load_trips.dart
index dbf7aa7..6506e77 100644
--- a/frontend/lib/utils/load_trips.dart
+++ b/frontend/lib/utils/load_trips.dart
@@ -8,7 +8,7 @@ class SavedTrips extends ChangeNotifier {
 
   List<Trip> get trips => _trips;
 
-  void loadTrips() async {
+  Future<List<Trip>> loadTrips() async {
     SharedPreferences prefs = await SharedPreferences.getInstance();
 
     List<Trip> trips = [];
@@ -21,6 +21,7 @@ class SavedTrips extends ChangeNotifier {
     }
     _trips = trips;
     notifyListeners();
+    return trips;
   }
 
   void addTrip(Trip trip) async {
-- 
2.47.2


From a676af3a67dcc91989bebc4d3e71349ebbc7130f Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sun, 23 Mar 2025 20:05:18 +0100
Subject: [PATCH 7/7] automatically save a trip when it is first created

---
 frontend/lib/modules/current_trip_save_button.dart | 2 --
 frontend/lib/utils/fetch_trip.dart                 | 5 ++++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/frontend/lib/modules/current_trip_save_button.dart b/frontend/lib/modules/current_trip_save_button.dart
index 64028e7..32d7ba6 100644
--- a/frontend/lib/modules/current_trip_save_button.dart
+++ b/frontend/lib/modules/current_trip_save_button.dart
@@ -19,8 +19,6 @@ class _saveButtonState extends State<saveButton> {
     return ElevatedButton(
       onPressed: () async {
         savedTrips.addTrip(widget.trip);
-        // SharedPreferences prefs = await SharedPreferences.getInstance();
-        // setState(() => widget.trip.toPrefs(prefs));
         rootScaffoldMessengerKey.currentState!.showSnackBar(
           SnackBar(
             content: Text('Trip saved'),
diff --git a/frontend/lib/utils/fetch_trip.dart b/frontend/lib/utils/fetch_trip.dart
index b243f0d..a1beb12 100644
--- a/frontend/lib/utils/fetch_trip.dart
+++ b/frontend/lib/utils/fetch_trip.dart
@@ -1,5 +1,6 @@
 import "dart:convert";
 import "dart:developer";
+import "package:anyway/main.dart";
 import 'package:dio/dio.dart';
 
 import 'package:anyway/constants.dart';
@@ -82,6 +83,8 @@ fetchTrip(
     }
 
   log(response.data.toString());
+  // Also save the trip for the user's convenience
+  savedTrips.addTrip(trip);
   }
 }
 
@@ -113,7 +116,7 @@ Future<(Landmark, String?)> fetchLandmark(String uuid) async {
   if (response.data["detail"] != null) {
     throw Exception(response.data["detail"]);
   }
-  log(response.data.toString());
+  // log(response.data.toString());
   Map<String, dynamic> json = response.data;
   String? nextUUID = json["next_uuid"];
   Landmark landmark = Landmark.fromJson(json);
-- 
2.47.2