From 3006f621207357ebfa0abcfb4e6fe6dda25ade6a Mon Sep 17 00:00:00 2001
From: Amal Nanavati <amaln@uw.edu>
Date: Mon, 15 Jan 2024 19:39:45 -0800
Subject: [PATCH] Allow users to customize the distance to mouth during bite
 transfer (#113)

* [WIP] Implemented getting/setting parameter

TODO:
- Implement "Try It" along with error handling
- Test it

* Separated DetectingFace into two components for easier reuse

* Generalized RobotMotion to be called within Settings

* Remove dependency on generic props

* Finished implementing MVP bite transfer customizatipn

* Clip allowable distances to mouth

* Finalized it in sim

* Removed combo MoveFromMouthTo..., made 'Done' restore pre-Settings robot arm configuration

* Small fixes from sim testing

* Formatting
---
 feedingwebapp/package-lock.json               | 1874 ++++++++++++++++-
 feedingwebapp/package.json                    |    1 +
 feedingwebapp/src/Pages/Constants.js          |   20 +-
 feedingwebapp/src/Pages/Footer/Footer.jsx     |   47 +-
 feedingwebapp/src/Pages/GlobalState.jsx       |  108 +-
 feedingwebapp/src/Pages/Header/Header.jsx     |   21 +-
 feedingwebapp/src/Pages/Home/Home.jsx         |   88 +-
 .../src/Pages/Home/MealStates/BiteDone.jsx    |  176 +-
 .../Home/MealStates/CircleProgressBar.jsx     |    2 +-
 .../Pages/Home/MealStates/DetectingFace.jsx   |  134 +-
 .../MealStates/DetectingFaceSubcomponent.jsx  |  152 ++
 .../src/Pages/Home/MealStates/RobotMotion.jsx |   85 +-
 feedingwebapp/src/Pages/Home/VideoFeed.jsx    |    7 +-
 .../src/Pages/Settings/BiteTransfer.jsx       |  510 +++++
 feedingwebapp/src/Pages/Settings/Main.jsx     |  112 +
 feedingwebapp/src/Pages/Settings/Settings.jsx |   88 +-
 feedingwebapp/src/ros/ros_helpers.js          |   32 +
 feedingwebapp/src/webrtc/webrtc_helpers.js    |    4 +-
 18 files changed, 2975 insertions(+), 486 deletions(-)
 create mode 100644 feedingwebapp/src/Pages/Home/MealStates/DetectingFaceSubcomponent.jsx
 create mode 100644 feedingwebapp/src/Pages/Settings/BiteTransfer.jsx
 create mode 100644 feedingwebapp/src/Pages/Settings/Main.jsx

diff --git a/feedingwebapp/package-lock.json b/feedingwebapp/package-lock.json
index d4485108..a44f5970 100644
--- a/feedingwebapp/package-lock.json
+++ b/feedingwebapp/package-lock.json
@@ -8,6 +8,7 @@
       "name": "feedingwebapp",
       "version": "0.1.0",
       "dependencies": {
+        "@fluentui/react-components": "^9.44.1",
         "@mapbox/node-pre-gyp": "^1.0.11",
         "@testing-library/jest-dom": "^5.16.4",
         "@testing-library/react": "^13.2.0",
@@ -2219,74 +2220,1817 @@
         "postcss-selector-parser": "^6.0.10"
       }
     },
+    "node_modules/@emotion/hash": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
+      "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ=="
+    },
     "node_modules/@emotion/is-prop-valid": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
       "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==",
       "dependencies": {
-        "@emotion/memoize": "^0.8.1"
+        "@emotion/memoize": "^0.8.1"
+      }
+    },
+    "node_modules/@emotion/memoize": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
+      "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
+    },
+    "node_modules/@emotion/stylis": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
+      "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ=="
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+      "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+      "dependencies": {
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.5.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
+      "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
+      "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.5.2",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "8.40.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz",
+      "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@floating-ui/core": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz",
+      "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==",
+      "dependencies": {
+        "@floating-ui/utils": "^0.2.0"
+      }
+    },
+    "node_modules/@floating-ui/devtools": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.0.4.tgz",
+      "integrity": "sha512-lSlvB45PgGS+YmGtOPseYBLwa+u+wPsZ+g/bT5kgzK2zLAKR5m9L5hS3b/OFZhrFWwehRf73RRSZ/WXg4r5WMw==",
+      "peerDependencies": {
+        "@floating-ui/dom": ">=1.5.4"
+      }
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz",
+      "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==",
+      "dependencies": {
+        "@floating-ui/core": "^1.5.3",
+        "@floating-ui/utils": "^0.2.0"
+      }
+    },
+    "node_modules/@floating-ui/utils": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
+      "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
+    },
+    "node_modules/@fluentui/keyboard-keys": {
+      "version": "9.0.7",
+      "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.7.tgz",
+      "integrity": "sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==",
+      "dependencies": {
+        "@swc/helpers": "^0.5.1"
+      }
+    },
+    "node_modules/@fluentui/keyboard-keys/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/priority-overflow": {
+      "version": "9.1.11",
+      "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.1.11.tgz",
+      "integrity": "sha512-sdrpavvKX2kepQ1d6IaI3ObLq5SAQBPRHPGx2+wiMWL7cEx9vGGM0fmeicl3soqqmM5uwCmWnZk9QZv9XOY98w==",
+      "dependencies": {
+        "@swc/helpers": "^0.5.1"
+      }
+    },
+    "node_modules/@fluentui/priority-overflow/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-accordion": {
+      "version": "9.3.34",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.3.34.tgz",
+      "integrity": "sha512-kg6qUmDKFi2hY/HAcRIPpeXafOySHJcU5TguOoX1NCDfd0k9hj6facCD+b3uPt6HXBEALETAg0udcu+qNuSyPQ==",
+      "dependencies": {
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-accordion/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-alert": {
+      "version": "9.0.0-beta.99",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.99.tgz",
+      "integrity": "sha512-2uWDRjAypS3yU6tmr57dqn8YdSAtR+BHE9n+kCsIprO52tBoFTrf27HZAITzLqCNSDf5X43K3k66ijJ7VZPFcw==",
+      "dependencies": {
+        "@fluentui/react-avatar": "^9.6.4",
+        "@fluentui/react-button": "^9.3.61",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-alert/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-aria": {
+      "version": "9.6.2",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.6.2.tgz",
+      "integrity": "sha512-DMM4l5fMfg7yltqM33TFlEJlua7eAqIdLnKtnQ4szezbG2QZOy+a+qmJOGNcScteuO1/kRfYC+WOXhxtnMeA7g==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-aria/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-avatar": {
+      "version": "9.6.4",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.6.4.tgz",
+      "integrity": "sha512-ziQ2KshcoV5rccmB1X2Hl0IYWJEor0OEcX2e4ki5BgCEI2JbYtd/rKQvw60kYyddqU3Vb7u9fThtxBu3o806eA==",
+      "dependencies": {
+        "@fluentui/react-badge": "^9.2.19",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-popover": "^9.8.28",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-tooltip": "^9.4.6",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-avatar/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-badge": {
+      "version": "9.2.19",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.2.19.tgz",
+      "integrity": "sha512-6HjUNeNV1KkSTuft+8YtPd5tfbJKJA5g0HO/8+M7h803cr0zhyyokPOZuKM/tH5r9VCWa+gPoyaHRZUiWyHqIA==",
+      "dependencies": {
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-badge/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-breadcrumb": {
+      "version": "9.0.7",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.0.7.tgz",
+      "integrity": "sha512-/Kmp8CJxpW7ymTHAhSi9e09btPRhZG//oaSP6AGtTR5/0A8N1Kd+rDfmlvTleRWDn8+MMth+azt+amRaenNouQ==",
+      "dependencies": {
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-button": "^9.3.61",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-link": "^9.2.4",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-breadcrumb/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-button": {
+      "version": "9.3.61",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.3.61.tgz",
+      "integrity": "sha512-QYNZj6CxCbOJ0wKwhDx2QaAW4udS+vw4hlLcUUHZGnksYXrJt9vhKcflokShLpOKQikD9cPn+T8b5QzFGy2Skw==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-button/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-card": {
+      "version": "9.0.60",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.0.60.tgz",
+      "integrity": "sha512-ykohMAPtGor2RXZJeQFjwitVhhu03cq6I79WTgHnQIQvwyZ9RiHHYJ8QKsQzDpdyleSqOcUA6O6yk3oiVKVjNw==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-card/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-checkbox": {
+      "version": "9.2.5",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.2.5.tgz",
+      "integrity": "sha512-lfodSwu83BeDPaZRHNftqWmIrv8m9SeHdOODuAp1VPDWUCNtZkajZZaHXv77RQRKsF/O4Q60bOy0QtTsRkTqzg==",
+      "dependencies": {
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-checkbox/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-combobox": {
+      "version": "9.5.38",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.5.38.tgz",
+      "integrity": "sha512-AtvzKYCkzm0zSWSstx+q42HkejmZNfO3iH++fD3Z94e1jDdUD+KSLBpCTumskTvPLWPE6LlqhyYDKPjBK3bbOg==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-portal": "^9.4.7",
+        "@fluentui/react-positioning": "^9.11.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-combobox/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-components": {
+      "version": "9.44.1",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.44.1.tgz",
+      "integrity": "sha512-Qc3ItWXXsE4MdfzCGuzbqfA4StD8zijKOdlgPo7KrJdJ6hcXI7sDmkOMmjRJmcrDMyKPvoIPENr8emGqFbdklA==",
+      "dependencies": {
+        "@fluentui/react-accordion": "^9.3.34",
+        "@fluentui/react-alert": "9.0.0-beta.99",
+        "@fluentui/react-avatar": "^9.6.4",
+        "@fluentui/react-badge": "^9.2.19",
+        "@fluentui/react-breadcrumb": "^9.0.7",
+        "@fluentui/react-button": "^9.3.61",
+        "@fluentui/react-card": "^9.0.60",
+        "@fluentui/react-checkbox": "^9.2.5",
+        "@fluentui/react-combobox": "^9.5.38",
+        "@fluentui/react-dialog": "^9.9.3",
+        "@fluentui/react-divider": "^9.2.55",
+        "@fluentui/react-drawer": "^9.0.7",
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-image": "^9.1.52",
+        "@fluentui/react-infobutton": "9.0.0-beta.83",
+        "@fluentui/react-infolabel": "^9.0.11",
+        "@fluentui/react-input": "^9.4.57",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-link": "^9.2.4",
+        "@fluentui/react-menu": "^9.12.40",
+        "@fluentui/react-message-bar": "^9.0.12",
+        "@fluentui/react-overflow": "^9.1.5",
+        "@fluentui/react-persona": "^9.2.63",
+        "@fluentui/react-popover": "^9.8.28",
+        "@fluentui/react-portal": "^9.4.7",
+        "@fluentui/react-positioning": "^9.11.0",
+        "@fluentui/react-progress": "^9.1.57",
+        "@fluentui/react-provider": "^9.13.5",
+        "@fluentui/react-radio": "^9.2.0",
+        "@fluentui/react-select": "^9.1.57",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-skeleton": "^9.0.45",
+        "@fluentui/react-slider": "^9.1.62",
+        "@fluentui/react-spinbutton": "^9.2.57",
+        "@fluentui/react-spinner": "^9.3.35",
+        "@fluentui/react-switch": "^9.1.62",
+        "@fluentui/react-table": "^9.11.0",
+        "@fluentui/react-tabs": "^9.4.3",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-tags": "^9.0.17",
+        "@fluentui/react-text": "^9.4.4",
+        "@fluentui/react-textarea": "^9.3.57",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-toast": "^9.3.23",
+        "@fluentui/react-toolbar": "^9.1.62",
+        "@fluentui/react-tooltip": "^9.4.6",
+        "@fluentui/react-tree": "^9.4.20",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@fluentui/react-virtualizer": "9.0.0-alpha.63",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-components/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-context-selector": {
+      "version": "9.1.46",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.46.tgz",
+      "integrity": "sha512-CDoGob3p9ZRL7AwzrxAjTPHJIjGvdMOfa+oIFL7O6EHATvU/7BQUPcCRPvhfZK4N4jD1w7AJgYwPPgkOqYbHpw==",
+      "dependencies": {
+        "@fluentui/react-utilities": "^9.15.6",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-context-selector/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-dialog": {
+      "version": "9.9.3",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.9.3.tgz",
+      "integrity": "sha512-WAQgrbt/I1X0XcLDnMt+qmAx30E3Ol/auJhACLhilkht/uQ6xoeWOjRGBY2k6yMA32QpLqdGbV4UA4EcLLBuSg==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-portal": "^9.4.7",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1",
+        "react-transition-group": "^4.4.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-dialog/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-divider": {
+      "version": "9.2.55",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.2.55.tgz",
+      "integrity": "sha512-WbV5nDhqe+2JXq4Igv7eZHrAB4v+CbICGhJ+sY86uHd9872hjBr9cHUSpBnY8yeffXc/PSmjF+i1NcmCOyHUyg==",
+      "dependencies": {
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-divider/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-drawer": {
+      "version": "9.0.7",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.0.7.tgz",
+      "integrity": "sha512-XKG5m+vFQvBl92R9O6LQOUMPSOqzh1KsR3iZQehfhcticEuShi0uIK9ys0/atYJ890ErWjuXPF7cJHvNU5IYXg==",
+      "dependencies": {
+        "@fluentui/react-dialog": "^9.9.3",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-motion-preview": "^0.5.7",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-drawer/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-field": {
+      "version": "9.1.47",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.1.47.tgz",
+      "integrity": "sha512-FXVjdHkhEVr8bRKoKoZRFvrW5ZAU3ZRq4EUxMvZDOxfeVx0cxo8qIG2BOp2xe4GrVXyfVtq0Fguqx58ttlG5sg==",
+      "dependencies": {
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-field/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-icons": {
+      "version": "2.0.224",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.224.tgz",
+      "integrity": "sha512-ld03dlc1pG7xeTQsK1y5in19jkMtWHNaoktFv+e7NV2xmrgV/SgPyyjEXbMrQHb8Naea/XCoCpNHnUNCy68akw==",
+      "dependencies": {
+        "@griffel/react": "^1.0.0",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-image": {
+      "version": "9.1.52",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.1.52.tgz",
+      "integrity": "sha512-gKlf1LJXAgvyUrYlskxk58ZHMF05v0tk21G9HMWczEiivThgigsrwIRtGC2jJI66Op8c5VLdZ8/wrNK5s43k2Q==",
+      "dependencies": {
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-image/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-infobutton": {
+      "version": "9.0.0-beta.83",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.83.tgz",
+      "integrity": "sha512-qPY9DSBv70jTl5M6YJMEYDyVPsD5D47GsTmKiuaohm9xMjXs3JUpnmve9E0uTCwQmxKRt57qvMfBSD3PCpdO7Q==",
+      "dependencies": {
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-popover": "^9.8.28",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-infobutton/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-infolabel": {
+      "version": "9.0.11",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.0.11.tgz",
+      "integrity": "sha512-St74bRh14W+m5ClHIMJTqqut0PCtgo18Of1G9fQBAs7hEQuTMtj8hPWJHJsXAl70CovjaBZg3cADfXGS/WtfYw==",
+      "dependencies": {
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-popover": "^9.8.28",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.8.0 <19.0.0",
+        "@types/react-dom": ">=16.8.0 <19.0.0",
+        "react": ">=16.8.0 <19.0.0",
+        "react-dom": ">=16.8.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-infolabel/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-input": {
+      "version": "9.4.57",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.4.57.tgz",
+      "integrity": "sha512-zWcUzHQitMR6etKn2b0BvqjSiZxyX3LQ5XEdG2VW2QyXyF/sa+NTEOxiyqSo9Gk4wS3TO0WQb/3cPyMiubSWYQ==",
+      "dependencies": {
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-input/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-jsx-runtime": {
+      "version": "9.0.24",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.0.24.tgz",
+      "integrity": "sha512-aWnu04Cfz7RmRYuL/ra2V5vfH0KVjP6dBAy6I+MntxY4m9QwyJ3cS0Z/CzqmexW57w2VjR8+J5uNGATSlwcuuw==",
+      "dependencies": {
+        "@fluentui/react-utilities": "^9.15.6",
+        "@swc/helpers": "^0.5.1",
+        "react-is": "^17.0.2"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-jsx-runtime/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-label": {
+      "version": "9.1.55",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.1.55.tgz",
+      "integrity": "sha512-lgWsw0F0g8qa5lHITvWbJpEinvhr5iMlX8/O73ynn2N4tt1Ltqx9HPld/J5E40s3KUZQCgYgTwCu3bw3/AbT5w==",
+      "dependencies": {
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-label/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-link": {
+      "version": "9.2.4",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.2.4.tgz",
+      "integrity": "sha512-zO/DONs1ay5B2VfYH6pfZVsjSanKmMI1S0HqSk7pdGtkp8XhwRFl+G3Xm+v9J4aKfvakJEMemTCRNcHiuCwwsA==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-link/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-menu": {
+      "version": "9.12.40",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.12.40.tgz",
+      "integrity": "sha512-GLjAjTRiO1dByfr5yGPrO7rA3HgwkbVCV4j8t8vh64yi3I0cmnXC7S3Wv2KOD0oIVMDnwEozk3kBvjmy3RfwAw==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-portal": "^9.4.7",
+        "@fluentui/react-positioning": "^9.11.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-menu/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-message-bar": {
+      "version": "9.0.12",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.0.12.tgz",
+      "integrity": "sha512-/ysREhZ0CckNukrRr5S6SNdXJBJWxNlJoYuzYLFxiRV9xj05+EXpuoKxsQwaG5LMkl5I+x+tf3WuPBKJs9FcXA==",
+      "dependencies": {
+        "@fluentui/react-button": "^9.3.61",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1",
+        "react-transition-group": "^4.4.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.8.0 <19.0.0",
+        "@types/react-dom": ">=16.8.0 <19.0.0",
+        "react": ">=16.8.0 <19.0.0",
+        "react-dom": ">=16.8.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-message-bar/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-motion-preview": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-motion-preview/-/react-motion-preview-0.5.7.tgz",
+      "integrity": "sha512-RODcicznqfrMzHTwrs62JCOi9S+vS/W1VOJ/KQFS7SLh7DgyZuNRz6mqZwbZMy3xHibli4qITMnLrwOzBg7Lhg==",
+      "dependencies": {
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-motion-preview/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-overflow": {
+      "version": "9.1.5",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.1.5.tgz",
+      "integrity": "sha512-8qdOL8MSnT0UeXRY9gVnzKgMx/LqmStTqGsY+luKDgmXxkzlc2hqx9SLnByry1ljDPVpI1LtOku9U6YZhGeg4g==",
+      "dependencies": {
+        "@fluentui/priority-overflow": "^9.1.11",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-overflow/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-persona": {
+      "version": "9.2.63",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.2.63.tgz",
+      "integrity": "sha512-W0eqsXr1M2WhLuxYU1pi/5dsZnM/zF6HPUuU7k/kSZF5Psi+ad9mYSOo6xKVgQ8UCaX5acJpkIYa+ExpgwJP3w==",
+      "dependencies": {
+        "@fluentui/react-avatar": "^9.6.4",
+        "@fluentui/react-badge": "^9.2.19",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-persona/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-popover": {
+      "version": "9.8.28",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.8.28.tgz",
+      "integrity": "sha512-gKehi0BrEyZaRBNMzk6cywU9q3dfz5spKWndA4zuaYv4sFOfwVVaa4NfoHY1nPTd2/6xawLPSxO5JMxCZESuug==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-portal": "^9.4.7",
+        "@fluentui/react-positioning": "^9.11.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-popover/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-portal": {
+      "version": "9.4.7",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.4.7.tgz",
+      "integrity": "sha512-4g0vvs+YKmBri24MBi+C3hkgKAEGhbNUi4+u1Oa0olrcGmbtugM0G910raDLJXLV2ssgSO8znzVRmA/4Lg7XYw==",
+      "dependencies": {
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1",
+        "use-disposable": "^1.0.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-portal/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-positioning": {
+      "version": "9.11.0",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.11.0.tgz",
+      "integrity": "sha512-kLtnAHpHkJLDIFctNfpDDbGBy5jw0n3ydGAvsiGVvcvBp4q0Ecy8d0ELLlwryVTxI8imdmeM/wkPOzz4LqS49A==",
+      "dependencies": {
+        "@floating-ui/devtools": "0.0.4",
+        "@floating-ui/dom": "^1.2.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-positioning/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-progress": {
+      "version": "9.1.57",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.1.57.tgz",
+      "integrity": "sha512-QFBz9A9N4lyshev1b/r7OE5ea7/Q60Tav3zVGbfqVGmfA24qemmoDIYU1qWscuScRBmblR6//fvAroHhiK/FrQ==",
+      "dependencies": {
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-progress/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-provider": {
+      "version": "9.13.5",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.13.5.tgz",
+      "integrity": "sha512-oxpGS8r5YEKHZy2csH9/kCJBgBMVms+HC0hiIA+J3M2iCdN+y1SuP0Y2zAYg/X/jRb1mXJzXtoWchsYvxVLnOQ==",
+      "dependencies": {
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/core": "^1.14.1",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-provider/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
       }
     },
-    "node_modules/@emotion/memoize": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
-      "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
+    "node_modules/@fluentui/react-radio": {
+      "version": "9.2.0",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.2.0.tgz",
+      "integrity": "sha512-TowAnE7aMDq3fxCiouetjs8CN4KogfaarXYep3pXQMW7xRKBfXdOOFElYtQx/WzmikMJpDhhkZcyrqEpM5KGDQ==",
+      "dependencies": {
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
     },
-    "node_modules/@emotion/stylis": {
-      "version": "0.8.5",
-      "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
-      "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ=="
+    "node_modules/@fluentui/react-radio/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
     },
-    "node_modules/@eslint-community/eslint-utils": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
-      "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+    "node_modules/@fluentui/react-select": {
+      "version": "9.1.57",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.1.57.tgz",
+      "integrity": "sha512-QGlK+QYDiAzA6f3imGQBQOq9MQVVa88XyaSKWG82mjZfFWbs6vxaIZMXuCOTAsjcXKB4XDYVYOpman3apdLHjQ==",
       "dependencies": {
-        "eslint-visitor-keys": "^3.3.0"
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
       },
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-select/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-shared-contexts": {
+      "version": "9.13.2",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.13.2.tgz",
+      "integrity": "sha512-78aEZdff7vaUOmeRyMDPc/Ml+kbwn02BiRLPQhqgYtCyjy0V3YBpmYfqxO8N5hUIZcFTedyOaHWpzVeEYxpNmA==",
+      "dependencies": {
+        "@fluentui/react-theme": "^9.1.16",
+        "@swc/helpers": "^0.5.1"
       },
       "peerDependencies": {
-        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+        "@types/react": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0"
       }
     },
-    "node_modules/@eslint-community/regexpp": {
-      "version": "4.5.1",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
-      "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
-      "engines": {
-        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+    "node_modules/@fluentui/react-shared-contexts/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
       }
     },
-    "node_modules/@eslint/eslintrc": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
-      "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
+    "node_modules/@fluentui/react-skeleton": {
+      "version": "9.0.45",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.0.45.tgz",
+      "integrity": "sha512-toOWQNoqONupLImvbkE4vf+ECq1lAyCUBf4hI6AOtYppDaXOOOWWsgSImsj25yLtS4dPYkzyWoMMdmjSOwXu6g==",
       "dependencies": {
-        "ajv": "^6.12.4",
-        "debug": "^4.3.2",
-        "espree": "^9.5.2",
-        "globals": "^13.19.0",
-        "ignore": "^5.2.0",
-        "import-fresh": "^3.2.1",
-        "js-yaml": "^4.1.0",
-        "minimatch": "^3.1.2",
-        "strip-json-comments": "^3.1.1"
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
       },
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-skeleton/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-slider": {
+      "version": "9.1.62",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.1.62.tgz",
+      "integrity": "sha512-GHY1J3qpoYY3c1rwQsBRTHISExO1vBSJCH4lDgCJI/E9KOa8saJYFvuv3aYmnOq8CGSb2UCSb0eha5G9UB/4yQ==",
+      "dependencies": {
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
       },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
       }
     },
-    "node_modules/@eslint/js": {
-      "version": "8.40.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz",
-      "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==",
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+    "node_modules/@fluentui/react-slider/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-spinbutton": {
+      "version": "9.2.57",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.2.57.tgz",
+      "integrity": "sha512-FoYe0iUcEYjlhJtqjciBdQ/4wuQ7iPwpqE/VuGknvWrydXawJ7qI3fx7yP/58R5utbGAz4Rdkkjzc2xhtW/EVg==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-spinbutton/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-spinner": {
+      "version": "9.3.35",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.3.35.tgz",
+      "integrity": "sha512-0JXgkVrB4+atN1P44XtuNup6xthg4gyJYPXGS+3x/EB2B0pi55c8IWE/mVjG9F/TBt2PFRb9nCzdrfvkhV/CsA==",
+      "dependencies": {
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-spinner/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-switch": {
+      "version": "9.1.62",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.1.62.tgz",
+      "integrity": "sha512-L+MzTP3B5eWxw7az62Sf7FGzPhPQoD0CtyR78IHTrgPXQswnoSq9oJRkpVr5LBfND2SE4Y7UvPuUulBJXTlW5g==",
+      "dependencies": {
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-label": "^9.1.55",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-switch/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-table": {
+      "version": "9.11.0",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.11.0.tgz",
+      "integrity": "sha512-Hp7PBg0iy5W+y7j4QKIyzHd4dpdvIzcyvzYevTkJNWALyUzzZZ6yefLS+hHy/akP/gEOGctnNyJENiODBSSbAA==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-avatar": "^9.6.4",
+        "@fluentui/react-checkbox": "^9.2.5",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-radio": "^9.2.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-table/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-tabs": {
+      "version": "9.4.3",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.4.3.tgz",
+      "integrity": "sha512-H/bM6NfA3y81NdOMmCWMhpv4SDAWkxMq8ywx8Pr98pKvkearlIo9EuxFK84YEK0haibgn6OpWSPciVaBLx8dPw==",
+      "dependencies": {
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0",
+        "scheduler": "^0.19.0 || ^0.20.0"
+      }
+    },
+    "node_modules/@fluentui/react-tabs/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-tabster": {
+      "version": "9.17.0",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.17.0.tgz",
+      "integrity": "sha512-+tFYkjH5QiF2YDCmJAz1FVzzs/09hiRT0xPe1yLlAkMYJV/s+iIungwKgSUF1RziP9iQh9NZZ2A5GMrzRw8SGg==",
+      "dependencies": {
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1",
+        "keyborg": "^2.3.0",
+        "tabster": "^5.0.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-tabster/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-tags": {
+      "version": "9.0.17",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.0.17.tgz",
+      "integrity": "sha512-XV3mtMgPcbXwDlrXVU19hfW0MsXmhM+ZHS0oZgR/jSDO6Nses6jdS3qiG2+Nl/AJqW6wA2l2yCBXHdAZu7hC8A==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-avatar": "^9.6.4",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-tags/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-text": {
+      "version": "9.4.4",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.4.4.tgz",
+      "integrity": "sha512-FH/zua+u+T8QK1cDeg4w1Ahdfj+2A3Wd61g9lxU26ZfUzhWxV7F9enwGgiqTF0Swv7WsD1ahwI+FIZA5+WgEsw==",
+      "dependencies": {
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-text/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-textarea": {
+      "version": "9.3.57",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.3.57.tgz",
+      "integrity": "sha512-E26jQ1s7/QLkJjTw72BQHfKtXP8PyNsfPSfWbwhmm5doe0HLa1V5+Gq1ZkdQiV78Q5Rl0bGKXrdR2Ccy/fBL/g==",
+      "dependencies": {
+        "@fluentui/react-field": "^9.1.47",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-textarea/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-theme": {
+      "version": "9.1.16",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.16.tgz",
+      "integrity": "sha512-QK2dGE5aQXN1UGdiEmGKpYGP3tHXIchLvFf8DEEOWnF4XBc9SiEPNFYkvLMJjHxZmDz4D670rsOPe0r5jFDEKQ==",
+      "dependencies": {
+        "@fluentui/tokens": "1.0.0-alpha.13",
+        "@swc/helpers": "^0.5.1"
+      }
+    },
+    "node_modules/@fluentui/react-theme/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-toast": {
+      "version": "9.3.23",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.3.23.tgz",
+      "integrity": "sha512-PJClzPYWmq303SoaNuPwgF0Drbn0pGrzqA6x8J3NgCx7F4c8n5SB34jxKtKlFAB5EiAk1y+v1om7Z6/v+3Zehg==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-portal": "^9.4.7",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1",
+        "react-transition-group": "^4.4.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-toast/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-toolbar": {
+      "version": "9.1.62",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.1.62.tgz",
+      "integrity": "sha512-97mlwQsAXn5jYhvyUUU7FrMIwddN5CTQEpoTDOaibcZ1hvZTNyVDyLpvWy7CLjX8CPvde/jgjf4z+I74zYP0OA==",
+      "dependencies": {
+        "@fluentui/react-button": "^9.3.61",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-divider": "^9.2.55",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-radio": "^9.2.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-toolbar/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-tooltip": {
+      "version": "9.4.6",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.4.6.tgz",
+      "integrity": "sha512-G3u6Qdr8mBClcncmf4qzIiPx4ti1ZjhB/lFVYIyB8Egg6s20TBRajo3ZlTD+Wwo9In8szfLm836bz8SMZqL4KA==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-portal": "^9.4.7",
+        "@fluentui/react-positioning": "^9.11.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-tooltip/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-tree": {
+      "version": "9.4.20",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.4.20.tgz",
+      "integrity": "sha512-LTzGiJeKCXYHUB7gY/XiQcowTVirz402Oeb6As8WM99pmWAzmttzSTiS7+MeHqJEeisNzOojyR8bcqRJ3DY7Pg==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-aria": "^9.6.2",
+        "@fluentui/react-avatar": "^9.6.4",
+        "@fluentui/react-button": "^9.3.61",
+        "@fluentui/react-checkbox": "^9.2.5",
+        "@fluentui/react-context-selector": "^9.1.46",
+        "@fluentui/react-icons": "^2.0.224",
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-radio": "^9.2.0",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-tabster": "^9.17.0",
+        "@fluentui/react-theme": "^9.1.16",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-tree/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-utilities": {
+      "version": "9.15.6",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.15.6.tgz",
+      "integrity": "sha512-Hli0iiA/gaWwADMe7NRD6TSy7KvL3bgek8j1sYkE9BiUI89GqyfJwU2Tm0it04iiCYvQ5WWrXPcRYyZ3/MHtpA==",
+      "dependencies": {
+        "@fluentui/keyboard-keys": "^9.0.7",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-utilities/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/react-virtualizer": {
+      "version": "9.0.0-alpha.63",
+      "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.63.tgz",
+      "integrity": "sha512-Uddb1bIayzXwSEJg90ybNUa1NE84aOCFRKAf1E2by7mSQupyOk3NjrVSpm3O78vUdPyjJN+COZlTsEFE3EBbIg==",
+      "dependencies": {
+        "@fluentui/react-jsx-runtime": "^9.0.24",
+        "@fluentui/react-shared-contexts": "^9.13.2",
+        "@fluentui/react-utilities": "^9.15.6",
+        "@griffel/react": "^1.5.14",
+        "@swc/helpers": "^0.5.1"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.0 <19.0.0",
+        "@types/react-dom": ">=16.14.0 <19.0.0",
+        "react": ">=16.14.0 <19.0.0",
+        "react-dom": ">=16.14.0 <19.0.0"
+      }
+    },
+    "node_modules/@fluentui/react-virtualizer/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@fluentui/tokens": {
+      "version": "1.0.0-alpha.13",
+      "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.13.tgz",
+      "integrity": "sha512-IzYysTTBkAH7tQZxYKpzhxYnTJkvwXhjhTOpmERgnqTFifHTP8/vaQjJAAm7dI/9zlDx1oN+y/I+KzL9bDLHZQ==",
+      "dependencies": {
+        "@swc/helpers": "^0.5.1"
+      }
+    },
+    "node_modules/@fluentui/tokens/node_modules/@swc/helpers": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
+      "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@griffel/core": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.15.1.tgz",
+      "integrity": "sha512-09w5axbOJuBzjTVFN5EycbAOIpCoxZeoJMZgT2fTrIl2GIxnTWpK3F2d63UzGBmQf1O+EgR6nK4FgMXFt1UFig==",
+      "dependencies": {
+        "@emotion/hash": "^0.9.0",
+        "@griffel/style-types": "^1.0.2",
+        "csstype": "^3.1.2",
+        "rtl-css-js": "^1.16.1",
+        "stylis": "^4.2.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@griffel/react": {
+      "version": "1.5.19",
+      "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.19.tgz",
+      "integrity": "sha512-qefnZseAwcwCpFVzN33mG20t/hofpWci7VNtOwzSco/IxFLuJaB2ffki+uAdUgWCpV2A67bWQjXNlymBoMUysg==",
+      "dependencies": {
+        "@griffel/core": "^1.15.1",
+        "tslib": "^2.1.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0 <19.0.0"
+      }
+    },
+    "node_modules/@griffel/style-types": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.0.2.tgz",
+      "integrity": "sha512-ka/Tpl1WU8js88LObwB/4EvpgXzx/EEJfbHhAr4ZNt29hrQKgL93X1zSY6M/FRhMhWrGIawauWkZP6/y6w/WiQ==",
+      "dependencies": {
+        "csstype": "^3.1.2"
       }
     },
     "node_modules/@humanwhocodes/config-array": {
@@ -12961,6 +14705,11 @@
         "node": ">=4.0"
       }
     },
+    "node_modules/keyborg": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.4.0.tgz",
+      "integrity": "sha512-EixFnyCc6m27NkFwyT5GNNQl+9wiTMePtAvVuKXZpc0CZLLJfJFB3zXGFBGnwtvEXymbJoPWoErzwTpiEQ+Msg=="
+    },
     "node_modules/kleur": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@@ -16791,6 +18540,14 @@
         "react-dom": "^18.2.0"
       }
     },
+    "node_modules/rtl-css-js": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz",
+      "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==",
+      "dependencies": {
+        "@babel/runtime": "^7.1.2"
+      }
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -17574,6 +19331,11 @@
       "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz",
       "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA=="
     },
+    "node_modules/stylis": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz",
+      "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ=="
+    },
     "node_modules/sucrase": {
       "version": "3.32.0",
       "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
@@ -17841,6 +19603,15 @@
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
       "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
     },
+    "node_modules/tabster": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/tabster/-/tabster-5.2.0.tgz",
+      "integrity": "sha512-cSi3a0gGeM9Co/gTKHlhTFfiitwVjcA+kP9lJux0U7QaRrZox1yYrfbwZhJXM7N0fux7BgvCYaOxME5k0EQ0tA==",
+      "dependencies": {
+        "keyborg": "^2.2.0",
+        "tslib": "^2.3.1"
+      }
+    },
     "node_modules/tailwindcss": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
@@ -18557,6 +20328,17 @@
         "requires-port": "^1.0.0"
       }
     },
+    "node_modules/use-disposable": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/use-disposable/-/use-disposable-1.0.2.tgz",
+      "integrity": "sha512-UMaXVlV77dWOu4GqAFNjRzHzowYKUKbJBQfCexvahrYeIz4OkUYUjna4Tjjdf92NH8Nm8J7wEfFRgTIwYjO5jg==",
+      "peerDependencies": {
+        "@types/react": ">=16.8.0 <19.0.0",
+        "@types/react-dom": ">=16.8.0 <19.0.0",
+        "react": ">=16.8.0 <19.0.0",
+        "react-dom": ">=16.8.0 <19.0.0"
+      }
+    },
     "node_modules/use-sync-external-store": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
diff --git a/feedingwebapp/package.json b/feedingwebapp/package.json
index d1935619..93b1d99d 100644
--- a/feedingwebapp/package.json
+++ b/feedingwebapp/package.json
@@ -3,6 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@fluentui/react-components": "^9.44.1",
     "@mapbox/node-pre-gyp": "^1.0.11",
     "@testing-library/jest-dom": "^5.16.4",
     "@testing-library/react": "^13.2.0",
diff --git a/feedingwebapp/src/Pages/Constants.js b/feedingwebapp/src/Pages/Constants.js
index 39fe6386..ab82a840 100644
--- a/feedingwebapp/src/Pages/Constants.js
+++ b/feedingwebapp/src/Pages/Constants.js
@@ -23,11 +23,9 @@ export const TIME_TO_RESET_MS = 3600000 // 1 hour in milliseconds
  */
 let MOVING_STATE_ICON_DICT = {}
 MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingAbovePlate] = '/robot_state_imgs/move_above_plate_position.svg'
-MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingFromMouthToAbovePlate] = '/robot_state_imgs/move_above_plate_position.svg'
 MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToRestingPosition] = '/robot_state_imgs/move_to_resting_position.svg'
-MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingFromMouthToRestingPosition] = '/robot_state_imgs/move_to_resting_position.svg'
 MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToStagingConfiguration] = '/robot_state_imgs/move_to_staging_configuration.svg'
-MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingFromMouthToStagingConfiguration] = '/robot_state_imgs/move_to_staging_configuration.svg'
+MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingFromMouth] = '/robot_state_imgs/move_to_staging_configuration.svg'
 MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToMouth] = '/robot_state_imgs/move_to_mouth_position.svg'
 MOVING_STATE_ICON_DICT[MEAL_STATE.R_StowingArm] = '/robot_state_imgs/stowing_arm_position.svg'
 export { MOVING_STATE_ICON_DICT }
@@ -69,10 +67,6 @@ ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingAbovePlate] = {
   actionName: 'MoveAbovePlate',
   messageType: 'ada_feeding_msgs/action/MoveTo'
 }
-ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingFromMouthToAbovePlate] = {
-  actionName: 'MoveFromMouthToAbovePlate',
-  messageType: 'ada_feeding_msgs/action/MoveTo'
-}
 ROS_ACTIONS_NAMES[MEAL_STATE.U_BiteSelection] = {
   actionName: 'SegmentFromPoint',
   messageType: 'ada_feeding_msgs/action/SegmentFromPoint'
@@ -85,16 +79,12 @@ ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingToRestingPosition] = {
   actionName: 'MoveToRestingPosition',
   messageType: 'ada_feeding_msgs/action/MoveTo'
 }
-ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingFromMouthToRestingPosition] = {
-  actionName: 'MoveFromMouthToRestingPosition',
-  messageType: 'ada_feeding_msgs/action/MoveTo'
-}
 ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingToStagingConfiguration] = {
   actionName: 'MoveToStagingConfiguration',
   messageType: 'ada_feeding_msgs/action/MoveTo'
 }
-ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingFromMouthToStagingConfiguration] = {
-  actionName: 'MoveFromMouthToStagingConfiguration',
+ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingFromMouth] = {
+  actionName: 'MoveFromMouth',
   messageType: 'ada_feeding_msgs/action/MoveTo'
 }
 ROS_ACTIONS_NAMES[MEAL_STATE.R_MovingToMouth] = {
@@ -119,6 +109,10 @@ ROS_SERVICE_NAMES[MEAL_STATE.R_DetectingFace] = {
 export { ROS_SERVICE_NAMES }
 export const CLEAR_OCTOMAP_SERVICE_NAME = 'clear_octomap'
 export const CLEAR_OCTOMAP_SERVICE_TYPE = 'std_srvs/srv/Empty'
+export const GET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/get_parameters'
+export const GET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/GetParameters'
+export const SET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/set_parameters'
+export const SET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/SetParameters'
 
 /**
  * The meaning of the status that motion actions return in their results.
diff --git a/feedingwebapp/src/Pages/Footer/Footer.jsx b/feedingwebapp/src/Pages/Footer/Footer.jsx
index ff2b6ea7..c80eeb0a 100644
--- a/feedingwebapp/src/Pages/Footer/Footer.jsx
+++ b/feedingwebapp/src/Pages/Footer/Footer.jsx
@@ -9,13 +9,13 @@ import { useMediaQuery } from 'react-responsive'
 import PropTypes from 'prop-types'
 // Local imports
 import { MOVING_STATE_ICON_DICT } from '../Constants'
-import { useGlobalState } from '../GlobalState'
 
 /**
  * The Footer shows a pause button. When users click it, the app tells the robot
  * to immediately pause and displays a back button that allows them to return to
  * previous state and a resume button that allows them to resume current state.
  *
+ * @param {string} mealState - the current meal state
  * @param {bool} paused - whether the robot is currently paused
  * @param {function} pauseCallback - callback function for when the pause button
  *     is clicked
@@ -27,14 +27,12 @@ import { useGlobalState } from '../GlobalState'
  *     button is clicked. If null, don't render the resume button.
  */
 const Footer = (props) => {
-  // Get the current meal state
-  const mealState = useGlobalState((state) => state.mealState)
   // Flag to check if the current orientation is portrait
   const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
   // Icons for the footer buttons
   let pauseIcon = '/robot_state_imgs/pause_button_icon.svg'
   let backIcon = props.backMealState ? MOVING_STATE_ICON_DICT[props.backMealState] : ''
-  let resumeIcon = MOVING_STATE_ICON_DICT[mealState]
+  let resumeIcon = MOVING_STATE_ICON_DICT[props.mealState]
   // Sizes (width, height, fontsize) of footer buttons
   let pauseButtonWidth = '98vw'
   let backResumeButtonWidth = '47vw'
@@ -95,7 +93,7 @@ const Footer = (props) => {
     (config) => {
       return (
         <>
-          <Row className='justify-content-center'>
+          <Row className='justify-content-center' style={{ width: '100%' }}>
             <Button
               variant={config.variant}
               disabled={config.disabled}
@@ -163,34 +161,37 @@ const Footer = (props) => {
 
   // Render the component
   return (
-    <View>
+    <View style={{ wdith: '100%' }}>
       <MDBFooter bgColor='dark' className='text-center text-lg-left' style={{ width: '100vw' }}>
         <div className='text-center' style={{ backgroundColor: 'rgba(0, 0, 0, 0.2)', paddingBottom: '5px', paddingTop: '5px' }}>
-          {props.paused ? (
-            <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: '100%' }}>
-              <View
-                style={{ flex: 5, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100%' }}
-              >
-                {props.backCallback ? renderFooterButton(buttonConfig.back) : <></>}
-              </View>
-              <View
-                style={{ flex: 5, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100%' }}
-              >
-                {props.resumeCallback ? renderFooterButton(buttonConfig.resume) : <></>}
-              </View>
-            </View>
-          ) : (
-            renderFooterButton(buttonConfig.pause)
-          )}
+          <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: '100%' }}>
+            {props.paused ? (
+              <>
+                <View
+                  style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100%' }}
+                >
+                  {props.backCallback ? renderFooterButton(buttonConfig.back) : <></>}
+                </View>
+                <View
+                  style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100%' }}
+                >
+                  {props.resumeCallback ? renderFooterButton(buttonConfig.resume) : <></>}
+                </View>
+              </>
+            ) : (
+              renderFooterButton(buttonConfig.pause)
+            )}
+          </View>
         </div>
       </MDBFooter>
     </View>
   )
 }
 Footer.propTypes = {
+  mealState: PropTypes.string.isRequired,
   paused: PropTypes.bool.isRequired,
   pauseCallback: PropTypes.func.isRequired,
-  // If any of the below three are null, the Footer won't render that button
+  // If any of the below two are null, the Footer won't render that button
   resumeCallback: PropTypes.func,
   backCallback: PropTypes.func,
   backMealState: PropTypes.string
diff --git a/feedingwebapp/src/Pages/GlobalState.jsx b/feedingwebapp/src/Pages/GlobalState.jsx
index 76de930d..892a626f 100644
--- a/feedingwebapp/src/Pages/GlobalState.jsx
+++ b/feedingwebapp/src/Pages/GlobalState.jsx
@@ -39,18 +39,9 @@ export const APP_PAGE = {
  *   - R_DetectingFace: Waiting for the robot to detect a face.
  *   - R_MovingToMouth: Waiting for the robot to finish moving to the user's
  *     mouth.
- *   - R_MovingFromMouthToStagingConfiguration: Waiting for the robot to move
+ *   - R_MovingFromMouth: Waiting for the robot to move
  *     from the user's mouth to the staging configuration. This is a separate
- *     action from R_MovingToStagingConfiguration to allow us to customize the
- *     departure from the mouth (e.g., a slower speed).
- *   - R_MovingFromMouthToAbovePlate: Waiting for the robot to move from the
- *     user's mouth to above the plate. This is a separate action from
- *     R_MovingAbovePlate to allow us to customize the departure from the mouth
- *     (e.g., a slower speed).
- *   - R_MovingFromMouthToRestingPosition: Waiting for the robot to move from
- *     the user's mouth to resting position. This is a separate action from
- *     R_MovingToRestingPosition to allow us to customize the departure from
- *     the mouth (e.g., a slower speed).
+ *     action from R_MovingToStagingConfiguration since it is cartesian.
  *   - U_BiteDone: Waiting for the user to indicate that they are done eating
  *     the bite.
  *   - R_StowingArm: Waiting for the robot to stow the arm.
@@ -67,14 +58,23 @@ export const MEAL_STATE = {
   R_MovingToStagingConfiguration: 'R_MovingToStagingConfiguration',
   R_DetectingFace: 'R_DetectingFace',
   R_MovingToMouth: 'R_MovingToMouth',
-  R_MovingFromMouthToStagingConfiguration: 'R_MovingFromMouthToStagingConfiguration',
-  R_MovingFromMouthToAbovePlate: 'R_MovingFromMouthToAbovePlate',
-  R_MovingFromMouthToRestingPosition: 'R_MovingFromMouthToRestingPosition',
+  R_MovingFromMouth: 'R_MovingFromMouth',
   U_BiteDone: 'U_BiteDone',
   R_StowingArm: 'R_StowingArm',
   U_PostMeal: 'U_PostMeal'
 }
 
+/**
+ * SETTINGS_STATE controls which settings page to display.
+ *  - MAIN: The main page, with options to navigate to the other pages.
+ *  - BITE_TRANSFER: The bite transfer page, where the user can configure
+ *    parameters for bite transfer.
+ */
+export const SETTINGS_STATE = {
+  MAIN: 'MAIN',
+  BITE_TRANSFER: 'BITE_TRANSFER'
+}
+
 /**
  * The parameters that users can set (keys) and a list of human-readable values
  * they can take on.
@@ -90,11 +90,11 @@ export const MEAL_STATE = {
  * TODO (amaln): When we connect this to ROS, each of these settings types and
  * value options will have to have corresponding rosparam names and value options.
  */
-export const SETTINGS = {
-  stagingPosition: ['In Front of Me', 'On My Right Side'],
-  biteInitiation: ['Open Mouth', 'Say "I am Ready"', 'Press Button'],
-  biteSelection: ['Name of Food', 'Click on Food']
-}
+// export const SETTINGS = {
+//   stagingPosition: ['In Front of Me', 'On My Right Side'],
+//   biteInitiation: ['Open Mouth', 'Say "I am Ready"', 'Press Button'],
+//   biteSelection: ['Name of Food', 'Click on Food']
+// }
 
 /**
  * useGlobalState is a hook to store and manipulate web app state that we want
@@ -104,12 +104,14 @@ export const SETTINGS = {
 export const useGlobalState = create(
   persist(
     (set) => ({
+      // The current app page
+      appPage: APP_PAGE.Home,
       // The app's current meal state
       mealState: MEAL_STATE.U_PreMeal,
       // The timestamp when the robot transitioned to its current meal state
       mealStateTransitionTime: Date.now(),
-      // The current app page
-      appPage: APP_PAGE.Home,
+      // The currently displayed settings page
+      settingsState: SETTINGS_STATE.MAIN,
       // The goal for the bite acquisition action, including the most recent
       // food item that the user selected in "bite selection"
       biteAcquisitionActionGoal: null,
@@ -123,20 +125,44 @@ export const useGlobalState = create(
       teleopIsMoving: false,
       // Flag to indicate whether to auto-continue after face detection
       faceDetectionAutoContinue: false,
+      // Whether the settings bite transfer page is currently at the user's face
+      // or not. This is in the off-chance that the mealState is not at the user's
+      // face, the settings page is, and the user refreshes -- the page should
+      // call MoveFromMouthToStaging instead of just MoveToStaging.
+      biteTransferPageAtFace: false,
+      // The button the user most recently clicked on the BiteDone page. In practice,
+      // this is the state we transition to after R_MovingFromMouth. In practice,
+      // it is either R_MovingAbovePlate, R_MovingToRestingPosition, or R_DetectingFace.
+      mostRecentBiteDoneResponse: MEAL_STATE.R_DetectingFace,
       // Settings values
-      stagingPosition: SETTINGS.stagingPosition[0],
-      biteInitiation: SETTINGS.biteInitiation[0],
-      biteSelection: SETTINGS.biteSelection[0],
+      // stagingPosition: SETTINGS.stagingPosition[0],
+      // biteInitiation: SETTINGS.biteInitiation[0],
+      // biteSelection: SETTINGS.biteSelection[0],
 
       // Setters for global state
-      setMealState: (mealState) =>
+      setAppPage: (appPage) =>
         set(() => ({
-          mealState: mealState,
-          mealStateTransitionTime: Date.now()
+          appPage: appPage,
+          settingsState: SETTINGS_STATE.MAIN,
+          // Sometimes the settings menu leaves the robot in a paused state.
+          // Thus, we reset it to an unpaused state.
+          paused: false
         })),
-      setAppPage: (appPage) =>
+      setMealState: (mealState, mostRecentBiteDoneResponse = null) =>
+        set(() => {
+          let retval = {
+            mealState: mealState,
+            mealStateTransitionTime: Date.now(),
+            biteTransferPageAtFace: false // Reset this flag when the meal state changes
+          }
+          if (mostRecentBiteDoneResponse) {
+            retval.mostRecentBiteDoneResponse = mostRecentBiteDoneResponse
+          }
+          return retval
+        }),
+      setSettingsState: (settingsState) =>
         set(() => ({
-          appPage: appPage
+          settingsState: settingsState
         })),
       setBiteAcquisitionActionGoal: (biteAcquisitionActionGoal) =>
         set(() => ({
@@ -158,18 +184,22 @@ export const useGlobalState = create(
         set(() => ({
           faceDetectionAutoContinue: faceDetectionAutoContinue
         })),
-      setStagingPosition: (stagingPosition) =>
-        set(() => ({
-          stagingPosition: stagingPosition
-        })),
-      setBiteInitiation: (biteInitiation) =>
-        set(() => ({
-          biteInitiation: biteInitiation
-        })),
-      setBiteSelection: (biteSelection) =>
+      setBiteTransferPageAtFace: (biteTransferPageAtFace) =>
         set(() => ({
-          biteSelection: biteSelection
+          biteTransferPageAtFace: biteTransferPageAtFace
         }))
+      // setStagingPosition: (stagingPosition) =>
+      //   set(() => ({
+      //     stagingPosition: stagingPosition
+      //   })),
+      // setBiteInitiation: (biteInitiation) =>
+      //   set(() => ({
+      //     biteInitiation: biteInitiation
+      //   })),
+      // setBiteSelection: (biteSelection) =>
+      //   set(() => ({
+      //     biteSelection: biteSelection
+      //   }))
     }),
     { name: 'ada_web_app_global_state' }
   )
diff --git a/feedingwebapp/src/Pages/Header/Header.jsx b/feedingwebapp/src/Pages/Header/Header.jsx
index 9b8ae112..2525584c 100644
--- a/feedingwebapp/src/Pages/Header/Header.jsx
+++ b/feedingwebapp/src/Pages/Header/Header.jsx
@@ -6,7 +6,7 @@ import Navbar from 'react-bootstrap/Navbar'
 import Nav from 'react-bootstrap/Nav'
 import { useMediaQuery } from 'react-responsive'
 // Toast generates a temporary pop-up with a timeout.
-import { ToastContainer /* , toast */ } from 'react-toastify'
+import { ToastContainer, toast } from 'react-toastify'
 import 'react-toastify/dist/ReactToastify.css'
 // ROS imports
 import { useROS } from '../../ros/ros_helpers'
@@ -63,13 +63,13 @@ const Header = (props) => {
    * started, take the user to the settings menu. Else, ask them to complete
    * or terminate the meal because modifying settings.
    */
-  // const settingsClicked = useCallback(() => {
-  //   if (mealState === MEAL_STATE.U_PreMeal || mealState === MEAL_STATE.U_PostMeal) {
-  //     setAppPage(APP_PAGE.Settings)
-  //   } else {
-  //     toast('Please complete or terminate the feeding process to access Settings.')
-  //   }
-  // }, [mealState, setAppPage])
+  const settingsClicked = useCallback(() => {
+    if (NON_MOVING_STATES.has(mealState)) {
+      setAppPage(APP_PAGE.Settings)
+    } else {
+      toast('Wait for robot motion to complete before accessing Settings.')
+    }
+  }, [mealState, setAppPage])
 
   // Render the component. The NavBar will stay fixed even as we vertically scroll.
   return (
@@ -107,14 +107,13 @@ const Header = (props) => {
             >
               Home
             </Nav.Link>
-            {/* TODO: Reinstate the settings menu when we implement settings! */}
-            {/* <Nav.Link
+            <Nav.Link
               onClick={settingsClicked}
               className='text-dark bg-info rounded mx-1 btn-lg btn-huge p-2'
               style={{ fontSize: textFontSize }}
             >
               Settings
-            </Nav.Link> */}
+            </Nav.Link>
           </Nav>
           {NON_MOVING_STATES.has(mealState) || paused || (mealState === MEAL_STATE.U_PlateLocator && teleopIsMoving === false) ? (
             <Nav>
diff --git a/feedingwebapp/src/Pages/Home/Home.jsx b/feedingwebapp/src/Pages/Home/Home.jsx
index 8578eec4..58431fde 100644
--- a/feedingwebapp/src/Pages/Home/Home.jsx
+++ b/feedingwebapp/src/Pages/Home/Home.jsx
@@ -32,6 +32,24 @@ function Home(props) {
   const setMoveToMouthActionGoal = useGlobalState((state) => state.setMoveToMouthActionGoal)
   const setMealState = useGlobalState((state) => state.setMealState)
   const setPaused = useGlobalState((state) => state.setPaused)
+  const biteAcquisitionActionGoal = useGlobalState((state) => state.biteAcquisitionActionGoal)
+  const moveToMouthActionGoal = useGlobalState((state) => state.moveToMouthActionGoal)
+  const mostRecentBiteDoneResponse = useGlobalState((state) => state.mostRecentBiteDoneResponse)
+
+  // Implement a wrapper around setMealState, that resets mostRecentBiteDoneResponse to
+  // R_DetectingFace if the mealState is mostRecentBiteDoneResponse. In other words,
+  // after you transition to that state once, you need to revisit BiteDone to transition
+  // again.
+  const setMealStateWrapper = useCallback(
+    (newMealState) => {
+      if (newMealState === mostRecentBiteDoneResponse) {
+        setMealState(newMealState, MEAL_STATE.R_DetectingFace)
+      } else {
+        setMealState(newMealState)
+      }
+    },
+    [mostRecentBiteDoneResponse, setMealState]
+  )
 
   /**
    * Implement time-based transition of states. This is so that after the user
@@ -49,10 +67,6 @@ function Home(props) {
     }
   }, [mealStateTransitionTime, setMealState, setPaused, setMoveToMouthActionGoal, setBiteAcquisitionActionGoal])
 
-  // Get the relevant global variables
-  const biteAcquisitionActionGoal = useGlobalState((state) => state.biteAcquisitionActionGoal)
-  const moveToMouthActionGoal = useGlobalState((state) => state.moveToMouthActionGoal)
-
   /**
    * All action inputs are constant. Note that we must be cautious if making
    * them non-constant, because the robot will re-execute an action every time
@@ -81,12 +95,15 @@ function Home(props) {
          */
         let currentMealState = MEAL_STATE.R_MovingAbovePlate
         let nextMealState = MEAL_STATE.U_BiteSelection
+        let backMealState = null
         let waitingText = 'Waiting to move above the plate...'
         return (
           <RobotMotion
             debug={props.debug}
             mealState={currentMealState}
+            setMealState={setMealStateWrapper}
             nextMealState={nextMealState}
+            backMealState={backMealState}
             actionInput={moveAbovePlateActionInput}
             waitingText={waitingText}
           />
@@ -105,12 +122,15 @@ function Home(props) {
          */
         let currentMealState = MEAL_STATE.R_BiteAcquisition
         let nextMealState = MEAL_STATE.U_BiteAcquisitionCheck
+        let backMealState = MEAL_STATE.R_MovingAbovePlate
         let waitingText = 'Waiting to acquire the food...'
         return (
           <RobotMotion
             debug={props.debug}
             mealState={currentMealState}
+            setMealState={setMealStateWrapper}
             nextMealState={nextMealState}
+            backMealState={backMealState}
             actionInput={biteAcquisitionActionInput}
             waitingText={waitingText}
           />
@@ -119,12 +139,15 @@ function Home(props) {
       case MEAL_STATE.R_MovingToRestingPosition: {
         let currentMealState = MEAL_STATE.R_MovingToRestingPosition
         let nextMealState = MEAL_STATE.U_BiteAcquisitionCheck
+        let backMealState = MEAL_STATE.R_MovingAbovePlate
         let waitingText = 'Waiting to move to the resting position...'
         return (
           <RobotMotion
             debug={props.debug}
             mealState={currentMealState}
+            setMealState={setMealStateWrapper}
             nextMealState={nextMealState}
+            backMealState={backMealState}
             actionInput={moveToRestingPositionActionInput}
             waitingText={waitingText}
           />
@@ -140,12 +163,15 @@ function Home(props) {
          */
         let currentMealState = MEAL_STATE.R_MovingToStagingConfiguration
         let nextMealState = MEAL_STATE.R_DetectingFace
+        let backMealState = MEAL_STATE.R_MovingToRestingPosition
         let waitingText = 'Waiting to move in front of you...'
         return (
           <RobotMotion
             debug={props.debug}
             mealState={currentMealState}
+            setMealState={setMealStateWrapper}
             nextMealState={nextMealState}
+            backMealState={backMealState}
             actionInput={moveToStagingConfigurationActionInput}
             waitingText={waitingText}
           />
@@ -161,67 +187,44 @@ function Home(props) {
          */
         let currentMealState = MEAL_STATE.R_MovingToMouth
         let nextMealState = MEAL_STATE.U_BiteDone
+        let backMealState = MEAL_STATE.R_MovingFromMouth
         let waitingText = 'Waiting to move to your mouth...'
         return (
           <RobotMotion
             debug={props.debug}
             mealState={currentMealState}
+            setMealState={setMealStateWrapper}
             nextMealState={nextMealState}
+            backMealState={backMealState}
             actionInput={moveToMouthActionInput}
             waitingText={waitingText}
           />
         )
       }
-      case MEAL_STATE.R_MovingFromMouthToStagingConfiguration: {
+      case MEAL_STATE.R_MovingFromMouth: {
         /**
          * We recreate currentMealState due to a race condition where sometimes
          * the app is performing a re-rendering and *then* the state is updated.
          */
-        let currentMealState = MEAL_STATE.R_MovingFromMouthToStagingConfiguration
-        let nextMealState = MEAL_STATE.R_DetectingFace
-        let waitingText = 'Waiting to move from your mouth to in front of you...'
+        let currentMealState = MEAL_STATE.R_MovingFromMouth
+        let nextMealState = mostRecentBiteDoneResponse
+        // Although slightly unintuitive, having backMealState being MovingAbovePlate
+        // is necessary so the user doesn't get stuck in a situation where they can't
+        // move above the plate.
+        let backMealState = MEAL_STATE.R_MovingAbovePlate
+        let waitingText = 'Waiting to away from your mouth...'
         return (
           <RobotMotion
             debug={props.debug}
             mealState={currentMealState}
+            setMealState={setMealStateWrapper}
             nextMealState={nextMealState}
+            backMealState={backMealState}
             actionInput={moveToStagingConfigurationActionInput}
             waitingText={waitingText}
           />
         )
       }
-      case MEAL_STATE.R_MovingFromMouthToAbovePlate: {
-        /**
-         * We recreate currentMealState due to a race condition where sometimes
-         * the app is performing a re-rendering and *then* the state is updated.
-         */
-        let currentMealState = MEAL_STATE.R_MovingFromMouthToAbovePlate
-        let nextMealState = MEAL_STATE.U_BiteSelection
-        let waitingText = 'Waiting to move from your mouth to above the plate...'
-        return (
-          <RobotMotion
-            debug={props.debug}
-            mealState={currentMealState}
-            nextMealState={nextMealState}
-            actionInput={moveAbovePlateActionInput}
-            waitingText={waitingText}
-          />
-        )
-      }
-      case MEAL_STATE.R_MovingFromMouthToRestingPosition: {
-        let currentMealState = MEAL_STATE.R_MovingFromMouthToRestingPosition
-        let nextMealState = MEAL_STATE.U_BiteAcquisitionCheck
-        let waitingText = 'Waiting to move from your mouth to the resting position...'
-        return (
-          <RobotMotion
-            debug={props.debug}
-            mealState={currentMealState}
-            nextMealState={nextMealState}
-            actionInput={moveToRestingPositionActionInput}
-            waitingText={waitingText}
-          />
-        )
-      }
       case MEAL_STATE.U_BiteDone: {
         return <BiteDone debug={props.debug} />
       }
@@ -232,12 +235,15 @@ function Home(props) {
          */
         let currentMealState = MEAL_STATE.R_StowingArm
         let nextMealState = MEAL_STATE.U_PostMeal
+        let backMealState = MEAL_STATE.R_MovingAbovePlate
         let waitingText = 'Waiting to get out of your way...'
         return (
           <RobotMotion
             debug={props.debug}
             mealState={currentMealState}
+            setMealState={setMealStateWrapper}
             nextMealState={nextMealState}
+            backMealState={backMealState}
             actionInput={moveToStowPositionActionInput}
             waitingText={waitingText}
           />
@@ -252,9 +258,11 @@ function Home(props) {
     }
   }, [
     mealState,
+    setMealStateWrapper,
     props.debug,
     props.webrtcURL,
     biteAcquisitionActionInput,
+    mostRecentBiteDoneResponse,
     moveAbovePlateActionInput,
     moveToMouthActionInput,
     moveToRestingPositionActionInput,
diff --git a/feedingwebapp/src/Pages/Home/MealStates/BiteDone.jsx b/feedingwebapp/src/Pages/Home/MealStates/BiteDone.jsx
index 5332d3ea..b2538deb 100644
--- a/feedingwebapp/src/Pages/Home/MealStates/BiteDone.jsx
+++ b/feedingwebapp/src/Pages/Home/MealStates/BiteDone.jsx
@@ -18,15 +18,17 @@ const BiteDone = () => {
   // Get the relevant global variables
   const setMealState = useGlobalState((state) => state.setMealState)
   // Get icon image for move above plate
-  let moveAbovePlateImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingFromMouthToAbovePlate]
+  let moveAbovePlateImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingAbovePlate]
   // Get icon image for move to resting position
-  let moveToRestingPositionImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingFromMouthToRestingPosition]
+  let moveToRestingPositionImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToRestingPosition]
+  // Get icom image for move to staging configuration
+  let moveToStagingConfigurationImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToStagingConfiguration]
   // Flag to check if the current orientation is portrait
   const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
   // Indicator of how to arrange screen elements based on orientation
   let dimension = isPortrait ? 'column' : 'row'
   // Font size for text
-  let textFontSize = isPortrait ? '3vh' : '3vw'
+  let textFontSize = isPortrait ? '3vh' : '2.5vw'
   let buttonWidth = isPortrait ? '30vh' : '30vw'
   let buttonHeight = isPortrait ? '20vh' : '20vw'
   let iconWidth = isPortrait ? '28vh' : '28vw'
@@ -36,96 +38,22 @@ const BiteDone = () => {
    * Callback function for when the user wants to move above plate.
    */
   const moveAbovePlate = useCallback(() => {
-    setMealState(MEAL_STATE.R_MovingFromMouthToAbovePlate)
+    setMealState(MEAL_STATE.R_MovingFromMouth, MEAL_STATE.R_MovingAbovePlate)
   }, [setMealState])
 
   /**
    * Callback function for when the user wants to move to resting position.
    */
   const moveToRestingPosition = useCallback(() => {
-    setMealState(MEAL_STATE.R_MovingFromMouthToRestingPosition)
+    setMealState(MEAL_STATE.R_MovingFromMouth, MEAL_STATE.R_MovingToRestingPosition)
   }, [setMealState])
 
   /**
-   * Get the bite finished text to render.
-   *
-   * @returns {JSX.Element} the bite finished text
-   */
-  const biteFinishedText = useCallback(() => {
-    return (
-      <>
-        {/* Ask the user whether they want to move to above plate position */}
-        <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize }}>
-          Bite finished? Move above plate.
-        </p>
-      </>
-    )
-  }, [textFontSize])
-
-  /**
-   * Get the bite finished button to render.
-   *
-   * @returns {JSX.Element} the bite finished button
+   * Callback function for when the user wants to move to the staging configuration.
    */
-  const biteFinishedButton = useCallback(() => {
-    return (
-      <>
-        {/* Icon to move above plate */}
-        <Button
-          variant='success'
-          className='mx-2 mb-2 btn-huge'
-          size='lg'
-          onClick={moveAbovePlate}
-          style={{ width: buttonWidth, height: buttonHeight }}
-        >
-          <img src={moveAbovePlateImage} alt='move_above_plate_image' className='center' style={{ width: iconWidth, height: iconHeight }} />
-        </Button>
-      </>
-    )
-  }, [moveAbovePlate, moveAbovePlateImage, buttonHeight, buttonWidth, iconHeight, iconWidth])
-
-  /**
-   * Get the take another bite text to render.
-   *
-   * @returns {JSX.Element} the take another bite text
-   */
-  const takeAnotherBiteText = useCallback(() => {
-    return (
-      <>
-        {/* Ask the user whether they want to move to resting position */}
-        <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize }}>
-          Take another bite? Move back.
-        </p>
-      </>
-    )
-  }, [textFontSize])
-
-  /**
-   * Get the take another bite button to render.
-   *
-   * @returns {JSX.Element} the take another bite button
-   */
-  const takeAnotherBiteButton = useCallback(() => {
-    return (
-      <>
-        {/* Icon to move to resting position */}
-        <Button
-          variant='warning'
-          className='mx-2 mb-2 btn-huge'
-          size='lg'
-          onClick={moveToRestingPosition}
-          style={{ width: buttonWidth, height: buttonHeight }}
-        >
-          <img
-            src={moveToRestingPositionImage}
-            alt='move_to_resting_image'
-            className='center'
-            style={{ width: iconWidth, height: iconHeight }}
-          />
-        </Button>
-      </>
-    )
-  }, [moveToRestingPosition, moveToRestingPositionImage, buttonHeight, buttonWidth, iconHeight, iconWidth])
+  const moveToStagingConfiguration = useCallback(() => {
+    setMealState(MEAL_STATE.R_MovingFromMouth, MEAL_STATE.R_DetectingFace)
+  }, [setMealState])
 
   /** Get the full page view
    *
@@ -134,17 +62,85 @@ const BiteDone = () => {
   const fullPageView = useCallback(() => {
     return (
       <View style={{ flex: 'auto', flexDirection: dimension, alignItems: 'center', justifyContent: 'center', width: '100%' }}>
-        <View style={{ flex: 5, alignItems: 'center', justifyContent: 'center' }}>
-          {biteFinishedText()}
-          {biteFinishedButton()}
+        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
+          {/* Ask the user whether they want to move to above plate position */}
+          <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize }}>
+            Move above plate
+          </p>
+          {/* Icon to move above plate */}
+          <Button
+            variant='success'
+            className='mx-2 mb-2 btn-huge'
+            size='lg'
+            onClick={moveAbovePlate}
+            style={{ width: buttonWidth, height: buttonHeight }}
+          >
+            <img
+              src={moveAbovePlateImage}
+              alt='move_above_plate_image'
+              className='center'
+              style={{ width: iconWidth, height: iconHeight }}
+            />
+          </Button>
+        </View>
+        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
+          {/* Ask the user whether they want to move to resting position */}
+          <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize }}>
+            Rest to the side
+          </p>
+          {/* Icon to move to resting position */}
+          <Button
+            variant='warning'
+            className='mx-2 mb-2 btn-huge'
+            size='lg'
+            onClick={moveToRestingPosition}
+            style={{ width: buttonWidth, height: buttonHeight }}
+          >
+            <img
+              src={moveToRestingPositionImage}
+              alt='move_to_resting_image'
+              className='center'
+              style={{ width: iconWidth, height: iconHeight }}
+            />
+          </Button>
         </View>
-        <View style={{ flex: 5, alignItems: 'center', justifyContent: 'center' }}>
-          {takeAnotherBiteText()}
-          {takeAnotherBiteButton()}
+        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
+          {/* Ask the user whether they want to move to resting position */}
+          <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize }}>
+            Move away from mouth
+          </p>
+          {/* Icon to move to resting position */}
+          <Button
+            variant='warning'
+            className='mx-2 mb-2 btn-huge'
+            size='lg'
+            onClick={moveToStagingConfiguration}
+            style={{ width: buttonWidth, height: buttonHeight }}
+          >
+            <img
+              src={moveToStagingConfigurationImage}
+              alt='move_to_staging_image'
+              className='center'
+              style={{ width: iconWidth, height: iconHeight }}
+            />
+          </Button>
         </View>
       </View>
     )
-  }, [dimension, biteFinishedButton, biteFinishedText, takeAnotherBiteButton, takeAnotherBiteText])
+  }, [
+    buttonHeight,
+    buttonWidth,
+    dimension,
+    iconHeight,
+    iconWidth,
+    moveAbovePlate,
+    moveAbovePlateImage,
+    moveToRestingPosition,
+    moveToRestingPositionImage,
+    moveToStagingConfiguration,
+    moveToStagingConfigurationImage,
+    textFontSize
+  ])
 
   // Render the component
   return <>{fullPageView()}</>
diff --git a/feedingwebapp/src/Pages/Home/MealStates/CircleProgressBar.jsx b/feedingwebapp/src/Pages/Home/MealStates/CircleProgressBar.jsx
index dd63b880..3644ee1c 100644
--- a/feedingwebapp/src/Pages/Home/MealStates/CircleProgressBar.jsx
+++ b/feedingwebapp/src/Pages/Home/MealStates/CircleProgressBar.jsx
@@ -21,7 +21,7 @@ export default function CircleProgressBar(props) {
   // Size variables for progressbar (width, height, fontsize) in portrait and landscape
   let circleWidth = isPortrait ? '90%' : null
   let circleHeight = isPortrait ? null : '90%'
-  let textFontSize = isPortrait ? '10vh' : '20vh'
+  let textFontSize = isPortrait ? '8vh' : '14vh'
 
   // useEffect React Hook is used to synchronize with RobotMotion.jsx data to render circle progress bar
   useEffect(() => {
diff --git a/feedingwebapp/src/Pages/Home/MealStates/DetectingFace.jsx b/feedingwebapp/src/Pages/Home/MealStates/DetectingFace.jsx
index 6093ea08..77087f6b 100644
--- a/feedingwebapp/src/Pages/Home/MealStates/DetectingFace.jsx
+++ b/feedingwebapp/src/Pages/Home/MealStates/DetectingFace.jsx
@@ -1,5 +1,5 @@
 // React Imports
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import React, { useCallback, useState } from 'react'
 // PropTypes is used to validate that the used props are in fact passed to this
 // Component
 import PropTypes from 'prop-types'
@@ -8,18 +8,10 @@ import { useMediaQuery } from 'react-responsive'
 import { View } from 'react-native'
 
 // Local Imports
-import { useROS, createROSService, createROSServiceRequest, subscribeToROSTopic, unsubscribeFromROSTopic } from '../../../ros/ros_helpers'
 import '../Home.css'
-import { convertRemToPixels } from '../../../helpers'
 import { useGlobalState, MEAL_STATE } from '../../GlobalState'
-import {
-  FACE_DETECTION_IMG_TOPIC,
-  FACE_DETECTION_TOPIC,
-  FACE_DETECTION_TOPIC_MSG,
-  MOVING_STATE_ICON_DICT,
-  ROS_SERVICE_NAMES
-} from '../../Constants'
-import VideoFeed from '../VideoFeed'
+import { MOVING_STATE_ICON_DICT } from '../../Constants'
+import DetectingFaceSubcomponent from './DetectingFaceSubcomponent'
 
 /**
  * The DetectingFace component appears after the robot has moved to the staging
@@ -50,20 +42,6 @@ const DetectingFace = (props) => {
   let iconWidth = 28
   let iconHeight = 16
   let sizeSuffix = isPortrait ? 'vh' : 'vw'
-  // The min and max distance from the camera to the face for the face to be
-  // conidered valid. NOTE: This must match the values in the MoveToMouth tree.
-  const min_face_distance = 0.4
-  const max_face_distance = 1.25
-  // Margin for the video feed and between the mask buttons. Note this cannot
-  // be re-defined per render, otherwise it messes up re-rendering order upon
-  // resize in VideoFeed.
-  const margin = useMemo(() => convertRemToPixels(1), [])
-
-  /**
-   * Connect to ROS, if not already connected. Put this in useRef to avoid
-   * re-connecting upon re-renders.
-   */
-  const ros = useRef(useROS().ros)
 
   /**
    * Callback function for proceeding to move to the mouth position.
@@ -96,75 +74,22 @@ const DetectingFace = (props) => {
   }, [setMealState, setMouthDetected])
 
   /**
-   * Subscribe to the ROS Topic with the face detection result. This is created
-   * in local state to avoid re-creating it upon every re-render.
+   * Callback for when a face is detected within the correct range.
    */
-  const faceDetectionCallback = useCallback(
+  const faceDetectedCallback = useCallback(
     (message) => {
-      console.log('Got face detection message', message)
-      if (message.is_face_detected) {
-        let distance =
-          (message.detected_mouth_center.point.x ** 2.0 +
-            message.detected_mouth_center.point.y ** 2.0 +
-            message.detected_mouth_center.point.z ** 2.0) **
-          0.5
-        if (distance > min_face_distance && distance < max_face_distance) {
-          setMouthDetected(true)
-          setMoveToMouthActionGoal({
-            face_detection: message
-          })
-          // Automatically move on to the next stage if a face is detected
-          if (faceDetectionAutoContinue) {
-            moveToMouthCallback()
-          }
-        }
+      console.log('Face detected callback')
+      setMouthDetected(true)
+      setMoveToMouthActionGoal({
+        face_detection: message
+      })
+      // Automatically move on to the next stage if a face is detected
+      if (faceDetectionAutoContinue) {
+        moveToMouthCallback()
       }
     },
     [faceDetectionAutoContinue, moveToMouthCallback, setMoveToMouthActionGoal]
   )
-  useEffect(() => {
-    let topic = subscribeToROSTopic(ros.current, FACE_DETECTION_TOPIC, FACE_DETECTION_TOPIC_MSG, faceDetectionCallback)
-    /**
-     * In practice, because the values passed in in the second argument of
-     * useEffect will not change on re-renders, this return statement will
-     * only be called when the component unmounts.
-     */
-    return () => {
-      unsubscribeFromROSTopic(topic, faceDetectionCallback)
-    }
-  }, [faceDetectionCallback])
-
-  /**
-   * Create the ROS Service. This is created in local state to avoid re-creating
-   * it upon every re-render.
-   */
-  let { serviceName, messageType } = ROS_SERVICE_NAMES[MEAL_STATE.R_DetectingFace]
-  let toggleFaceDetectionService = useRef(createROSService(ros.current, serviceName, messageType))
-
-  /**
-   * Toggles face detection on the first time this component is rendered, but
-   * not upon additional re-renders. See here for more details on how `useEffect`
-   * achieves this goal: https://stackoverflow.com/a/69264685
-   */
-  useEffect(() => {
-    // Create a service request
-    let request = createROSServiceRequest({ data: true })
-    // Call the service
-    let service = toggleFaceDetectionService.current
-    service.callService(request, (response) => console.log('Got toggle face detection service response', response))
-
-    /**
-     * In practice, because the values passed in in the second argument of
-     * useEffect will not change on re-renders, this return statement will
-     * only be called when the component unmounts.
-     */
-    return () => {
-      // Create a service request
-      let request = createROSServiceRequest({ data: false })
-      // Call the service
-      service.callService(request, (response) => console.log('Got toggle face detection service response', response))
-    }
-  }, [toggleFaceDetectionService])
 
   /** Get the full page view
    *
@@ -202,36 +127,7 @@ const DetectingFace = (props) => {
           }}
         >
           <View style={{ flex: 5, alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%' }}>
-            <View
-              style={{
-                flex: 1,
-                alignItems: 'center',
-                justifyContent: 'center',
-                width: '100%',
-                height: '100%'
-              }}
-            >
-              <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize.toString() + sizeSuffix }}>
-                {mouthDetected ? 'Mouth detected!' : 'Waiting to detect mouth...'}
-              </p>
-            </View>
-            <View
-              style={{
-                flex: 9,
-                alignItems: 'center',
-                width: '100%',
-                height: '100%'
-              }}
-            >
-              <VideoFeed
-                marginTop={margin}
-                marginBottom={margin}
-                marginLeft={margin}
-                marginRight={margin}
-                topic={FACE_DETECTION_IMG_TOPIC}
-                webrtcURL={props.webrtcURL}
-              />
-            </View>
+            <DetectingFaceSubcomponent faceDetectedCallback={faceDetectedCallback} webrtcURL={props.webrtcURL} />
           </View>
           <View style={{ flex: 3, alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%' }}>
             <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize.toString() + sizeSuffix }}>
@@ -328,8 +224,8 @@ const DetectingFace = (props) => {
   }, [
     dimension,
     otherDimension,
-    margin,
     mouthDetected,
+    faceDetectedCallback,
     moveToMouthCallback,
     moveToRestingCallback,
     moveAbovePlateCallback,
diff --git a/feedingwebapp/src/Pages/Home/MealStates/DetectingFaceSubcomponent.jsx b/feedingwebapp/src/Pages/Home/MealStates/DetectingFaceSubcomponent.jsx
new file mode 100644
index 00000000..0513c1aa
--- /dev/null
+++ b/feedingwebapp/src/Pages/Home/MealStates/DetectingFaceSubcomponent.jsx
@@ -0,0 +1,152 @@
+// React Imports
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import PropTypes from 'prop-types'
+import { useMediaQuery } from 'react-responsive'
+import { View } from 'react-native'
+
+// Local Imports
+import { useROS, createROSService, createROSServiceRequest, subscribeToROSTopic, unsubscribeFromROSTopic } from '../../../ros/ros_helpers'
+import '../Home.css'
+import { convertRemToPixels } from '../../../helpers'
+import { MEAL_STATE } from '../../GlobalState'
+import { FACE_DETECTION_IMG_TOPIC, FACE_DETECTION_TOPIC, FACE_DETECTION_TOPIC_MSG, ROS_SERVICE_NAMES } from '../../Constants'
+import VideoFeed from '../VideoFeed'
+
+/**
+ * The DetectingFace component appears after the robot has moved to the staging
+ * configuration. It displays the output of face detection, and automatically
+ * moves on to `R_MovingToMouth` when a face is detected.
+ */
+const DetectingFaceSubcomponent = (props) => {
+  // Keep track of whether a mouth has been detected or not
+  const [mouthDetected, setMouthDetected] = useState(false)
+  // Flag to check if the current orientation is portrait
+  const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
+  // Font size for text
+  let textFontSize = 3
+  let sizeSuffix = isPortrait ? 'vh' : 'vw'
+  // The min and max distance from the camera to the face for the face to be
+  // conidered valid. NOTE: This must match the values in the MoveToMouth tree.
+  const min_face_distance = 0.4
+  const max_face_distance = 1.25
+  // Margin for the video feed and between the mask buttons. Note this cannot
+  // be re-defined per render, otherwise it messes up re-rendering order upon
+  // resize in VideoFeed.
+  const margin = useMemo(() => convertRemToPixels(1), [])
+
+  /**
+   * Connect to ROS, if not already connected. Put this in useRef to avoid
+   * re-connecting upon re-renders.
+   */
+  const ros = useRef(useROS().ros)
+
+  /**
+   * Subscribe to the ROS Topic with the face detection result. This is created
+   * in local state to avoid re-creating it upon every re-render.
+   */
+  const faceDetectionCallback = useCallback(
+    (message) => {
+      console.log('Got face detection message', message)
+      let faceDetectedCallback = props.faceDetectedCallback
+      if (message.is_face_detected) {
+        let distance =
+          (message.detected_mouth_center.point.x ** 2.0 +
+            message.detected_mouth_center.point.y ** 2.0 +
+            message.detected_mouth_center.point.z ** 2.0) **
+          0.5
+        if (distance > min_face_distance && distance < max_face_distance) {
+          setMouthDetected(true)
+          faceDetectedCallback()
+        }
+      }
+    },
+    [props.faceDetectedCallback, setMouthDetected]
+  )
+  useEffect(() => {
+    let topic = subscribeToROSTopic(ros.current, FACE_DETECTION_TOPIC, FACE_DETECTION_TOPIC_MSG, faceDetectionCallback)
+    /**
+     * In practice, because the values passed in in the second argument of
+     * useEffect will not change on re-renders, this return statement will
+     * only be called when the component unmounts.
+     */
+    return () => {
+      unsubscribeFromROSTopic(topic, faceDetectionCallback)
+    }
+  }, [faceDetectionCallback])
+
+  /**
+   * Create the ROS Service. This is created in local state to avoid re-creating
+   * it upon every re-render.
+   */
+  let { serviceName, messageType } = ROS_SERVICE_NAMES[MEAL_STATE.R_DetectingFace]
+  let toggleFaceDetectionService = useRef(createROSService(ros.current, serviceName, messageType))
+
+  /**
+   * Toggles face detection on the first time this component is rendered, but
+   * not upon additional re-renders. See here for more details on how `useEffect`
+   * achieves this goal: https://stackoverflow.com/a/69264685
+   */
+  useEffect(() => {
+    // Create a service request
+    let request = createROSServiceRequest({ data: true })
+    // Call the service
+    let service = toggleFaceDetectionService.current
+    service.callService(request, (response) => console.log('Got toggle face detection service response', response))
+
+    /**
+     * In practice, because the values passed in in the second argument of
+     * useEffect will not change on re-renders, this return statement will
+     * only be called when the component unmounts.
+     */
+    return () => {
+      // Create a service request
+      let request = createROSServiceRequest({ data: false })
+      // Call the service
+      service.callService(request, (response) => console.log('Got toggle face detection service response', response))
+    }
+  }, [toggleFaceDetectionService])
+
+  // Render the component
+  return (
+    <>
+      <View
+        style={{
+          flex: 1,
+          alignItems: 'center',
+          justifyContent: 'center',
+          width: '100%',
+          height: '100%'
+        }}
+      >
+        <p className='transitionMessage' style={{ marginBottom: '0px', fontSize: textFontSize.toString() + sizeSuffix }}>
+          {mouthDetected ? 'Mouth detected!' : 'Waiting to detect mouth...'}
+        </p>
+      </View>
+      <View
+        style={{
+          flex: 9,
+          alignItems: 'center',
+          width: '100%',
+          height: '100%'
+        }}
+      >
+        <VideoFeed
+          marginTop={margin}
+          marginBottom={margin}
+          marginLeft={margin}
+          marginRight={margin}
+          topic={FACE_DETECTION_IMG_TOPIC}
+          webrtcURL={props.webrtcURL}
+        />
+      </View>
+    </>
+  )
+}
+DetectingFaceSubcomponent.propTypes = {
+  // The URL of the webrtc signalling server
+  webrtcURL: PropTypes.string.isRequired,
+  // The function to call, with the faceDetection message as an argument, when
+  // a face is detected within the correct distance range.
+  faceDetectedCallback: PropTypes.func.isRequired
+}
+export default DetectingFaceSubcomponent
diff --git a/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx b/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx
index 7c7f66d5..07dd3809 100644
--- a/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx
+++ b/feedingwebapp/src/Pages/Home/MealStates/RobotMotion.jsx
@@ -18,7 +18,7 @@ import {
 import Footer from '../../Footer/Footer'
 import CircleProgressBar from './CircleProgressBar'
 import '../Home.css'
-import { useGlobalState, MEAL_STATE } from '../../GlobalState'
+import { useGlobalState } from '../../GlobalState'
 import {
   CLEAR_OCTOMAP_SERVICE_NAME,
   CLEAR_OCTOMAP_SERVICE_TYPE,
@@ -60,8 +60,6 @@ const RobotMotion = (props) => {
   })
 
   // Get the relevant global variables
-  const mealState = useGlobalState((state) => state.mealState)
-  const setMealState = useGlobalState((state) => state.setMealState)
   const paused = useGlobalState((state) => state.paused)
   const setPaused = useGlobalState((state) => state.setPaused)
 
@@ -77,9 +75,9 @@ const RobotMotion = (props) => {
   // Indicator of how to arrange screen elements based on orientation
   let dimension = isPortrait ? 'column' : 'row'
   // Waiting text font size
-  let waitingTextFontSize = isPortrait ? '4.5vh' : '9vh'
+  let waitingTextFontSize = isPortrait ? '4.5vh' : '6vh'
   // Motion text font size
-  let motionTextFontSize = isPortrait ? '3vh' : '6vh'
+  let motionTextFontSize = isPortrait ? '3vh' : '4vh'
 
   /**
    * Create the ROS Action Client. This is re-created every time props.mealState
@@ -89,6 +87,7 @@ const RobotMotion = (props) => {
    * even if it momentarily differs from the global mealState.
    */
   let robotMotionAction = useMemo(() => {
+    console.log('Creating action client', props.mealState)
     let { actionName, messageType } = ROS_ACTIONS_NAMES[props.mealState]
     return createROSActionClient(ros.current, actionName, messageType)
   }, [props.mealState])
@@ -107,6 +106,7 @@ const RobotMotion = (props) => {
    */
   const feedbackCallback = useCallback(
     (feedbackMsg) => {
+      console.log('Got feedback message', feedbackMsg)
       setActionStatus({
         actionStatus: ROS_ACTION_STATUS_EXECUTE,
         feedback: feedbackMsg.values.feedback
@@ -121,8 +121,9 @@ const RobotMotion = (props) => {
    */
   const robotMotionDone = useCallback(() => {
     console.log('robotMotionDone')
+    let setMealState = props.setMealState
     setMealState(props.nextMealState)
-  }, [setMealState, props.nextMealState])
+  }, [props.nextMealState, props.setMealState])
 
   /**
    * Callback function for when the action sends a response. It updates the
@@ -137,6 +138,7 @@ const RobotMotion = (props) => {
    */
   const responseCallback = useCallback(
     (response) => {
+      console.log('Got response message', response)
       if (response.response_type === 'result' && response.values.status === MOTION_STATUS_SUCCESS) {
         setActionStatus({
           actionStatus: ROS_ACTION_STATUS_SUCCEED
@@ -178,6 +180,11 @@ const RobotMotion = (props) => {
    * is called it re-registers callbacks, so typically callbacks should only
    * be passed the first time it is called.
    *
+   * WARNING: If either pros.actionInput or pros.setMealState changes upon
+   * re-render, this function and the below useEffect will have unexpected
+   * behaviors (e.g., calling an action, then immediately destroying the
+   * action client, then calling it again, etc.)
+   *
    * @param {function} feedbackCb - the callback function for when the action
    * sends feedback
    * @param {function} responseCb - the callback function for when the action
@@ -246,38 +253,11 @@ const RobotMotion = (props) => {
     resumeCallback()
   }, [clearOctomapService, resumeCallback])
 
-  /**
-   * Callback function for when the back button is clicked. Regardless of the
-   * state, all pressed of "back" will revert to the "Moving Above Plate" state.
-   * - BiteAcquisition: In this case, pressing "back" should let the user
-   *   reselect the bite, which requires the robot to move above plate.
-   * - MoveToRestingPostion: In this case, pressing "back" should move the
-   *   robot back to the plate. Although the user may not always want to
-   *   reselect the bite, from `BiteSelection` they have the option to skip
-   *   BiteAcquisition and move straight to resting positon (when they are ready).
-   * - MoveToMouth: In this case, pressing "back" should move the
-   *   robot back to the resting positon.
-   * - StowingArm: In this case, if the user presses back they likely want to
-   *   eat another bite, hence moving above the plate makes sense.
-   * - MovingAbovePlate: Although the user may want to press "back" to move
-   *   the robot to the mouth, they can also go forward to
-   *   BiteSelection and then move the robot to the mouth location.
-   *   Hence, in this case we don't have a "back" button.
-   */
-  const backMealState = useRef(MEAL_STATE.R_MovingAbovePlate)
-  useEffect(() => {
-    if (mealState === MEAL_STATE.R_MovingToStagingConfiguration) {
-      backMealState.current = MEAL_STATE.R_MovingToRestingPosition
-    } else if (mealState === MEAL_STATE.R_MovingToMouth) {
-      backMealState.current = MEAL_STATE.R_MovingFromMouthToStagingConfiguration
-    } else {
-      backMealState.current = MEAL_STATE.R_MovingAbovePlate
-    }
-  }, [mealState, backMealState])
   const backCallback = useCallback(() => {
     setPaused(false)
-    setMealState(backMealState.current)
-  }, [setPaused, setMealState, backMealState])
+    let setMealState = props.setMealState
+    setMealState(props.backMealState)
+  }, [setPaused, props.backMealState, props.setMealState])
 
   /**
    * Get the action status text and progress bar or blank view to render.
@@ -303,7 +283,7 @@ const RobotMotion = (props) => {
                 {props.waitingText}
               </p>
               <p style={{ fontSize: motionTextFontSize }}>{text}</p>
-              {showTime ? <p style={{ fontSize: motionTextFontSize }}>&nbsp;&nbsp;Elapsed Time: {time} sec</p> : <></>}
+              {showTime ? <p style={{ fontSize: motionTextFontSize }}>&nbsp;&nbsp;Elapsed: {time} sec</p> : <></>}
               {retry ? (
                 <Button
                   variant='warning'
@@ -359,7 +339,7 @@ const RobotMotion = (props) => {
             if (!actionStatus.feedback.is_planning) {
               let moving_elapsed_time = actionStatus.feedback.motion_time.sec + actionStatus.feedback.motion_time.nanosec / 10 ** 9
               text = 'Robot is moving...'
-              time = Math.round(moving_elapsed_time * 100) / 100
+              time = Math.round(moving_elapsed_time * 10) / 10
               showTime = true
               progress = 1 - actionStatus.feedback.motion_curr_distance / actionStatus.feedback.motion_initial_distance
               // Calling CircleProgessBar component to visualize robot motion of moving
@@ -367,7 +347,7 @@ const RobotMotion = (props) => {
             } else {
               let planning_elapsed_time = actionStatus.feedback.planning_time.sec + actionStatus.feedback.planning_time.nanosec / 10 ** 9
               text = 'Robot is thinking...'
-              time = Math.round(planning_elapsed_time * 100) / 100
+              time = Math.round(planning_elapsed_time * 10) / 10
               showTime = true
               return <>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress)}</>
             }
@@ -387,7 +367,7 @@ const RobotMotion = (props) => {
            * users on how to troubleshoot/fix it.
            */
           text = 'Robot encountered an error'
-          retry = NON_RETRYABLE_STATES.has(mealState) ? false : true
+          retry = NON_RETRYABLE_STATES.has(props.mealState) ? false : true
           return (
             <>{actionStatusTextAndVisual(flexSizeOuter, flexSizeTextInner, flexSizeVisualInner, text, showTime, time, progress, retry)}</>
           )
@@ -407,7 +387,7 @@ const RobotMotion = (props) => {
           }
       }
     },
-    [paused, dimension, actionStatusTextAndVisual, mealState]
+    [paused, dimension, actionStatusTextAndVisual, props.mealState]
   )
 
   // Render the component
@@ -427,10 +407,11 @@ const RobotMotion = (props) => {
        * Display the footer with the Pause button.
        */}
       <Footer
+        mealState={props.mealState}
         pauseCallback={pauseCallback}
-        backCallback={mealState === MEAL_STATE.R_MovingAbovePlate ? null : backCallback}
-        backMealState={backMealState.current}
-        resumeCallback={NON_RETRYABLE_STATES.has(mealState) ? null : resumeCallback}
+        backCallback={props.backMealState ? backCallback : null}
+        backMealState={props.backMealState}
+        resumeCallback={NON_RETRYABLE_STATES.has(props.mealState) ? null : resumeCallback}
         paused={paused}
       />
     </>
@@ -445,12 +426,26 @@ RobotMotion.propTypes = {
   debug: PropTypes.bool.isRequired,
   // The meal state corresponding with the motion the robot is executing
   mealState: PropTypes.string.isRequired,
+  // The function for setting the meal state
+  // **WARNING**: If setMealState changes upon re-render, RobotMotion will have
+  // unexpected behaviors (e.g., calling an action, then immediately destroying
+  // the action client, then calling it again, etc.)
+  setMealState: PropTypes.func.isRequired,
   // The meal state to transition to once the robot finishes executing
-  nextMealState: PropTypes.string.isRequired,
+  nextMealState: PropTypes.string,
+  // The meal state to transition to if the user presses "back"
+  backMealState: PropTypes.string,
   // The input to provide to the ROS action
+  // **WARNING**: If actionInput changes upon re-render, RobotMotion will have
+  // unexpected behaviors (e.g., calling an action, then immediately destroying
+  // the action client, then calling it again, etc.)
   actionInput: PropTypes.object.isRequired,
   // The static text to display while the robot is executing the action
   waitingText: PropTypes.string.isRequired
 }
 
+RobotMotion.defaultProps = {
+  debug: false
+}
+
 export default RobotMotion
diff --git a/feedingwebapp/src/Pages/Home/VideoFeed.jsx b/feedingwebapp/src/Pages/Home/VideoFeed.jsx
index 333cf61b..63426883 100644
--- a/feedingwebapp/src/Pages/Home/VideoFeed.jsx
+++ b/feedingwebapp/src/Pages/Home/VideoFeed.jsx
@@ -173,13 +173,14 @@ const VideoFeed = (props) => {
       let x_raw = Math.round(x / scaleFactor) // x position within the raw image.
       let y_raw = Math.round(y / scaleFactor) // y position within the raw image.
       console.log('Button click on unscaled image: (' + x_raw + ', ' + y_raw + ')')
+      let pointClicked = props.pointClicked
 
       // Call the callback function if it exists
-      if (props.pointClicked) {
-        props.pointClicked(x_raw, y_raw)
+      if (pointClicked) {
+        pointClicked(x_raw, y_raw)
       }
     },
-    [props, scaleFactor]
+    [props.pointClicked, scaleFactor]
   )
 
   // Render the component
diff --git a/feedingwebapp/src/Pages/Settings/BiteTransfer.jsx b/feedingwebapp/src/Pages/Settings/BiteTransfer.jsx
new file mode 100644
index 00000000..a4169429
--- /dev/null
+++ b/feedingwebapp/src/Pages/Settings/BiteTransfer.jsx
@@ -0,0 +1,510 @@
+// React imports
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import PropTypes from 'prop-types'
+import { useId, Label, SpinButton } from '@fluentui/react-components'
+import Button from 'react-bootstrap/Button'
+// The Modal is a screen that appears on top of the main app, and can be toggled
+// on and off.
+import Modal from 'react-bootstrap/Modal'
+import { View } from 'react-native'
+
+// Local imports
+import { useROS, createROSService, createROSServiceRequest, getParameterValue } from '../../ros/ros_helpers'
+import {
+  GET_PARAMETERS_SERVICE_NAME,
+  GET_PARAMETERS_SERVICE_TYPE,
+  SET_PARAMETERS_SERVICE_NAME,
+  SET_PARAMETERS_SERVICE_TYPE
+} from '../Constants'
+import { useGlobalState, MEAL_STATE, SETTINGS_STATE } from '../GlobalState'
+import RobotMotion from '../Home/MealStates/RobotMotion'
+import DetectingFaceSubcomponent from '../Home/MealStates/DetectingFaceSubcomponent'
+
+/**
+ * The BiteTransfer component allows users to configure parameters related to the
+ * bite transfer.
+ */
+const BiteTransfer = (props) => {
+  // Get relevant global state variables
+  const setSettingsState = useGlobalState((state) => state.setSettingsState)
+  const globalMealState = useGlobalState((state) => state.mealState)
+  const setPaused = useGlobalState((state) => state.setPaused)
+  const biteTransferPageAtFace = useGlobalState((state) => state.biteTransferPageAtFace)
+  const setBiteTransferPageAtFace = useGlobalState((state) => state.setBiteTransferPageAtFace)
+
+  // Create relevant local state variables
+  // Store the current distance to mouth
+  const [currentDistanceToMouth, setCurrentDistanceToMouth] = useState(null)
+  const [localCurrAndNextMealState, setLocalCurrAndNextMealState] = useState(
+    globalMealState === MEAL_STATE.U_BiteDone || globalMealState === MEAL_STATE.R_DetectingFace || biteTransferPageAtFace
+      ? [MEAL_STATE.R_MovingFromMouth, null]
+      : [MEAL_STATE.R_MovingToStagingConfiguration, null]
+  )
+  const actionInput = useMemo(() => ({}), [])
+  const [doneButtonIsClicked, setDoneButtonIsClicked] = useState(false)
+
+  // Get min and max distance to mouth
+  const minDistanceToMouth = 1 // cm
+  const maxDistanceToMouth = 10 // cm
+
+  // When we set local meal state, also update bite transfer page at face
+  const setLocalCurrMealStateWrapper = useCallback(
+    (newLocalCurrMealState, newLocalNextMealState = null) => {
+      let oldLocalCurrMealState = localCurrAndNextMealState[0]
+      // If the oldlocalCurrMealState was R_MovingToMouth, then the robot is at the mouth
+      setBiteTransferPageAtFace(oldLocalCurrMealState === MEAL_STATE.R_MovingToMouth)
+      // Start in a moving state, not a paused state
+      setPaused(false)
+      if (newLocalCurrMealState === null && doneButtonIsClicked) {
+        // After the done button is clicked, the robot may have to do up to two
+        // motions to restore itself to its old state. After that, this goes
+        // back to the main settings page.
+        setSettingsState(SETTINGS_STATE.MAIN)
+      } else {
+        setLocalCurrAndNextMealState([newLocalCurrMealState, newLocalNextMealState])
+      }
+    },
+    [localCurrAndNextMealState, setLocalCurrAndNextMealState, setBiteTransferPageAtFace, doneButtonIsClicked, setPaused, setSettingsState]
+  )
+
+  // Store the props for the RobotMotion call. The first call has the robot move
+  // to the staging configuration.
+  const robotMotionProps = useMemo(() => {
+    let localCurrMealState = localCurrAndNextMealState[0]
+    let localNextMealState = localCurrAndNextMealState[1]
+    let waitingText
+    switch (localCurrMealState) {
+      case MEAL_STATE.R_MovingToStagingConfiguration:
+        waitingText = 'Waiting to move in front of you...'
+        break
+      case MEAL_STATE.R_MovingFromMouth:
+        waitingText = 'Waiting to move away from you...'
+        break
+      case MEAL_STATE.R_MovingToMouth:
+        waitingText = 'Waiting to move to your mouth...'
+        break
+      case MEAL_STATE.R_MovingAbovePlate:
+        waitingText = 'Waiting to move above the plate...'
+        break
+      case MEAL_STATE.R_MovingToRestingPosition:
+        waitingText = 'Waiting to move to the resting position...'
+        break
+      case MEAL_STATE.R_StowingArm:
+        waitingText = 'Waiting to stow the arm...'
+        break
+      default:
+        waitingText = 'Waiting to move in front of you...'
+        break
+    }
+    console.log('useMemo called with', localCurrMealState, waitingText)
+    return {
+      mealState: localCurrMealState,
+      setMealState: setLocalCurrMealStateWrapper,
+      nextMealState: localNextMealState,
+      backMealState: null,
+      actionInput: actionInput,
+      waitingText: waitingText
+    }
+  }, [localCurrAndNextMealState, setLocalCurrMealStateWrapper, actionInput])
+
+  // Rendering variables
+  let textFontSize = '3.5vh'
+
+  /**
+   * Connect to ROS, if not already connected. Put this in useRef to avoid
+   * re-connecting upon re-renders.
+   */
+  const ros = useRef(useROS().ros)
+
+  /**
+   * Create the ROS Service Clients to get/set parameters.
+   */
+  let getParametersService = useRef(createROSService(ros.current, GET_PARAMETERS_SERVICE_NAME, GET_PARAMETERS_SERVICE_TYPE))
+  let setParametersService = useRef(createROSService(ros.current, SET_PARAMETERS_SERVICE_NAME, SET_PARAMETERS_SERVICE_TYPE))
+
+  // The first time the page is rendered, get the current distance to mouth
+  useEffect(() => {
+    setDoneButtonIsClicked(false)
+    // Start in a moving state, not a paused state
+    setPaused(false)
+    let service = getParametersService.current
+    // First, attempt to get the current distance to mouth
+    let currentRequest = createROSServiceRequest({
+      names: ['current.MoveToMouth.tree_kwargs.plan_distance_from_mouth']
+    })
+    service.callService(currentRequest, (response) => {
+      console.log('Got current plan_distance_from_mouth response', response)
+      if (response.values[0].type === 0) {
+        // Parameter not set
+        // Second, attempt to get the default distance to mouth
+        let defaultRequest = createROSServiceRequest({
+          names: ['default.MoveToMouth.tree_kwargs.plan_distance_from_mouth']
+        })
+        service.callService(defaultRequest, (response) => {
+          console.log('Got default plan_distance_from_mouth response', response)
+          if (response.values.length > 0) {
+            setCurrentDistanceToMouth(getParameterValue(response.values[0]))
+          }
+        })
+      } else {
+        setCurrentDistanceToMouth(getParameterValue(response.values[0]))
+      }
+    })
+  }, [getParametersService, setCurrentDistanceToMouth, setDoneButtonIsClicked, setPaused])
+
+  // Callback to set the distance to mouth parameter
+  const setDistanceToMouth = useCallback(
+    (fullDistanceToMouth) => {
+      let service = setParametersService.current
+      let request = createROSServiceRequest({
+        parameters: [
+          {
+            name: 'current.MoveToMouth.tree_kwargs.plan_distance_from_mouth',
+            value: {
+              type: 8, // double array
+              double_array_value: fullDistanceToMouth
+            }
+          }
+        ]
+      })
+      service.callService(request, (response) => {
+        console.log('Got response', response)
+        if (response != null && response.results.length > 0 && response.results[0].successful) {
+          setCurrentDistanceToMouth(fullDistanceToMouth)
+        }
+      })
+    },
+    [setParametersService, setCurrentDistanceToMouth]
+  )
+
+  // Callback to restore the distance to mouth to the default
+  const restoreToDefaultButtonClicked = useCallback(() => {
+    let service = getParametersService.current
+    // Attempt to get the default distance to mouth
+    let defaultRequest = createROSServiceRequest({
+      names: ['default.MoveToMouth.tree_kwargs.plan_distance_from_mouth']
+    })
+    service.callService(defaultRequest, (response) => {
+      console.log('Got default plan_distance_from_mouth response', response)
+      if (response.values.length > 0) {
+        setDistanceToMouth(getParameterValue(response.values[0]))
+      }
+    })
+  }, [getParametersService, setDistanceToMouth])
+
+  // Callback to move the robot to the mouth
+  const moveToMouthButtonClicked = useCallback(() => {
+    setLocalCurrMealStateWrapper(MEAL_STATE.R_DetectingFace)
+    setDoneButtonIsClicked(false)
+  }, [setLocalCurrMealStateWrapper, setDoneButtonIsClicked])
+
+  // Callback to move the robot away from the mouth
+  const moveAwayFromMouthButtonClicked = useCallback(() => {
+    setLocalCurrMealStateWrapper(MEAL_STATE.R_MovingFromMouth)
+    setDoneButtonIsClicked(false)
+  }, [setLocalCurrMealStateWrapper, setDoneButtonIsClicked])
+
+  // Callback to return to the main settings page
+  const doneButtonClicked = useCallback(() => {
+    setDoneButtonIsClicked(true)
+    // Determine the state to move to based on the state before entering settings
+    let localNextMealState
+    // To get to Settings, the globalMealState must be one of the NON_MOVING_STATES
+    switch (globalMealState) {
+      case MEAL_STATE.U_BiteDone:
+        localNextMealState = null
+        break
+      case MEAL_STATE.U_PreMeal:
+      case MEAL_STATE.U_BiteSelection:
+        localNextMealState = MEAL_STATE.R_MovingAbovePlate
+        break
+      case MEAL_STATE.U_BiteAcquisitionCheck:
+        localNextMealState = MEAL_STATE.R_MovingToRestingPosition
+        break
+      case MEAL_STATE.U_PostMeal:
+        localNextMealState = MEAL_STATE.R_StowingArm
+        break
+      default:
+        localNextMealState = MEAL_STATE.R_MovingAbovePlate
+        break
+    }
+    setLocalCurrMealStateWrapper(MEAL_STATE.R_MovingFromMouth, localNextMealState)
+  }, [globalMealState, setLocalCurrMealStateWrapper, setDoneButtonIsClicked])
+
+  // Callback for when the user changes the distance to mouth
+  const onDistanceToMouthChange = useCallback(
+    (_ev, data) => {
+      let value = data.value ? data.value : parseFloat(data.displayValue)
+      if (value < minDistanceToMouth) {
+        value = minDistanceToMouth
+      }
+      if (value > maxDistanceToMouth) {
+        value = maxDistanceToMouth
+      }
+      let fullDistanceToMouth = [value / 100.0, currentDistanceToMouth[1], currentDistanceToMouth[2]]
+      setDistanceToMouth(fullDistanceToMouth)
+    },
+    [setDistanceToMouth, currentDistanceToMouth, minDistanceToMouth, maxDistanceToMouth]
+  )
+
+  // Callback to render the main contents of the page
+  const distanceToMouthId = useId()
+  const renderBiteTransferSettings = useCallback(() => {
+    if (currentDistanceToMouth === null) {
+      return (
+        <>
+          <View
+            style={{
+              flex: 1,
+              flexDirection: 'column',
+              justifyContent: 'center',
+              alignItems: 'center',
+              width: '100%'
+            }}
+          >
+            <h5 style={{ textAlign: 'center', fontSize: textFontSize }}>Loading...</h5>
+          </View>
+        </>
+      )
+    } else {
+      return (
+        <>
+          <View
+            style={{
+              flex: 8,
+              flexDirection: 'column',
+              justifyContent: 'center',
+              alignItems: 'center',
+              width: '100%'
+            }}
+          >
+            <Label
+              htmlFor={distanceToMouthId}
+              style={{
+                fontSize: textFontSize,
+                width: '90%',
+                color: 'black',
+                textAlign: 'center'
+              }}
+            >
+              Distance To Mouth (cm)
+            </Label>
+            <SpinButton
+              value={currentDistanceToMouth[0] * 100}
+              id={distanceToMouthId}
+              step={0.5}
+              onChange={onDistanceToMouthChange}
+              appearance='filled-lighter'
+              style={{
+                fontSize: textFontSize,
+                width: '90%',
+                color: 'black'
+              }}
+              incrementButton={{
+                'aria-label': 'Increase value by 0.5',
+                'aria-roledescription': 'spinner',
+                size: 'large'
+              }}
+            />
+            <Button
+              variant='warning'
+              className='mx-2 mb-2 btn-huge'
+              size='lg'
+              style={{
+                fontSize: textFontSize,
+                width: '60%',
+                color: 'black'
+              }}
+              onClick={restoreToDefaultButtonClicked}
+            >
+              Set to Default
+            </Button>
+          </View>
+          <View
+            style={{
+              flex: 2,
+              flexDirection: 'column',
+              justifyContent: 'center',
+              alignItems: 'center',
+              width: '100%'
+            }}
+          >
+            <Button
+              variant='warning'
+              className='mx-2 mb-2 btn-huge'
+              size='lg'
+              style={{
+                fontSize: textFontSize,
+                width: '90%',
+                height: '90%',
+                color: 'black'
+              }}
+              onClick={moveToMouthButtonClicked}
+            >
+              Move To Mouth
+            </Button>
+          </View>
+          <View
+            style={{
+              flex: 2,
+              flexDirection: 'column',
+              justifyContent: 'center',
+              alignItems: 'center',
+              width: '100%'
+            }}
+          />
+          <View
+            style={{
+              flex: 2,
+              flexDirection: 'column',
+              justifyContent: 'center',
+              alignItems: 'center',
+              width: '100%'
+            }}
+          >
+            <Button
+              variant='warning'
+              className='mx-2 mb-2 btn-huge'
+              size='lg'
+              style={{
+                fontSize: textFontSize,
+                width: '90%',
+                height: '90%',
+                color: 'black'
+              }}
+              onClick={moveAwayFromMouthButtonClicked}
+            >
+              Move From Mouth
+            </Button>
+          </View>
+          <View
+            style={{
+              flex: 2,
+              flexDirection: 'column',
+              justifyContent: 'center',
+              alignItems: 'center',
+              width: '100%'
+            }}
+          />
+        </>
+      )
+    }
+  }, [
+    textFontSize,
+    currentDistanceToMouth,
+    onDistanceToMouthChange,
+    distanceToMouthId,
+    moveToMouthButtonClicked,
+    moveAwayFromMouthButtonClicked,
+    restoreToDefaultButtonClicked
+  ])
+
+  // When a face is detected, switch to MoveToMouth
+  const faceDetectedCallback = useCallback(() => {
+    setLocalCurrMealStateWrapper(MEAL_STATE.R_MovingToMouth)
+  }, [setLocalCurrMealStateWrapper])
+
+  // Render the modal body, for calling robot code from within this settings page
+  const renderModalBody = useCallback(() => {
+    let localCurrMealState = localCurrAndNextMealState[0]
+    switch (localCurrMealState) {
+      case MEAL_STATE.R_MovingToStagingConfiguration:
+      case MEAL_STATE.R_MovingFromMouth:
+      case MEAL_STATE.R_MovingToMouth:
+      case MEAL_STATE.R_MovingAbovePlate:
+      case MEAL_STATE.R_MovingToRestingPosition:
+      case MEAL_STATE.R_StowingArm:
+        return (
+          <RobotMotion
+            mealState={robotMotionProps.mealState}
+            setMealState={robotMotionProps.setMealState}
+            nextMealState={robotMotionProps.nextMealState}
+            backMealState={robotMotionProps.backMealState}
+            actionInput={robotMotionProps.actionInput}
+            waitingText={robotMotionProps.waitingText}
+          />
+        )
+      case MEAL_STATE.R_DetectingFace:
+        return <DetectingFaceSubcomponent faceDetectedCallback={faceDetectedCallback} webrtcURL={props.webrtcURL} />
+      default:
+        return <></>
+    }
+  }, [localCurrAndNextMealState, props.webrtcURL, robotMotionProps, faceDetectedCallback])
+
+  return (
+    <>
+      <View
+        style={{
+          flex: 2,
+          flexDirection: 'column',
+          justifyContent: 'center',
+          alignItems: 'center',
+          width: '100%'
+        }}
+      >
+        <h5 style={{ textAlign: 'center', fontSize: textFontSize }}>Customize Bite Transfer</h5>
+      </View>
+      <View
+        style={{
+          flex: 16,
+          flexDirection: 'column',
+          justifyContent: 'center',
+          alignItems: 'center',
+          width: '100%'
+        }}
+      >
+        {renderBiteTransferSettings()}
+      </View>
+      <View
+        style={{
+          flex: 2,
+          flexDirection: 'column',
+          justifyContent: 'center',
+          alignItems: 'center',
+          width: '100%'
+        }}
+      >
+        <Button
+          variant='success'
+          className='mx-2 mb-2 btn-huge'
+          size='lg'
+          style={{
+            fontSize: textFontSize,
+            width: '90%',
+            height: '90%',
+            color: 'black'
+          }}
+          onClick={doneButtonClicked}
+        >
+          Done
+        </Button>
+      </View>
+      <Modal
+        show={localCurrAndNextMealState[0] !== null}
+        onHide={() => setLocalCurrMealStateWrapper(null)}
+        size='lg'
+        aria-labelledby='contained-modal-title-vcenter'
+        backdrop='static'
+        keyboard={false}
+        centered
+        id='robotMotionModal'
+        fullscreen={false}
+        dialogClassName='modal-90w'
+        style={{
+          '--bs-modal-padding': '0rem'
+        }}
+      >
+        <Modal.Header closeButton />
+        <Modal.Body style={{ overflow: 'hidden' }}>
+          <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', height: '65vh' }}>{renderModalBody()}</View>
+        </Modal.Body>
+      </Modal>
+    </>
+  )
+}
+BiteTransfer.propTypes = {
+  // The URL of the webrtc signalling server
+  webrtcURL: PropTypes.string.isRequired
+}
+
+export default BiteTransfer
diff --git a/feedingwebapp/src/Pages/Settings/Main.jsx b/feedingwebapp/src/Pages/Settings/Main.jsx
new file mode 100644
index 00000000..1bf0a1af
--- /dev/null
+++ b/feedingwebapp/src/Pages/Settings/Main.jsx
@@ -0,0 +1,112 @@
+// React imports
+import React from 'react'
+import Button from 'react-bootstrap/Button'
+import Container from 'react-bootstrap/Container'
+import Row from 'react-bootstrap/Row'
+import Image from 'react-bootstrap/Image'
+
+// Local imports
+import { MOVING_STATE_ICON_DICT } from '../Constants'
+import { useGlobalState, /* SETTINGS, */ MEAL_STATE, SETTINGS_STATE } from '../GlobalState'
+// import ToggleButtonGroup from '../../buttons/ToggleButtonGroup'
+
+/**
+ * The Main component displays all the settings users are able to configure.
+ */
+const Main = () => {
+  // Get relevant global state variables
+  const setSettingsState = useGlobalState((state) => state.setSettingsState)
+
+  // Get icon image for move to mouth
+  let moveToMouthConfigurationImage = MOVING_STATE_ICON_DICT[MEAL_STATE.R_MovingToMouth]
+
+  return (
+    <Container fluid>
+      {/**
+       * The title of the page.
+       */}
+      <Row className='justify-content-center mx-1 my-2'>
+        <h1 style={{ textAlign: 'center', fontSize: '40px' }} className='txt-huge'>
+          ⚙ Settings
+        </h1>
+      </Row>
+
+      <Row className='justify-content-center mx-1 my-2'>
+        <Button
+          variant='outline-dark'
+          style={{
+            fontSize: '30px',
+            display: 'flex',
+            flexDirection: 'row',
+            justifyContent: 'center',
+            alignItems: 'center',
+            height: '8vh',
+            borderWidth: '3px'
+          }}
+          onClick={() => setSettingsState(SETTINGS_STATE.BITE_TRANSFER)}
+        >
+          <Image
+            fluid
+            src={moveToMouthConfigurationImage}
+            style={{
+              height: '100%',
+              '--bs-btn-padding-x': '0rem',
+              '--bs-btn-padding-y': '0rem',
+              display: 'flex'
+            }}
+            alt='move_to_mouth_image'
+            className='center'
+          />
+          <p
+            style={{
+              display: 'flex',
+              marginTop: '1rem'
+            }}
+          >
+            Bite Transfer
+          </p>
+        </Button>
+      </Row>
+
+      {/**
+       * Load toggle-able buttons for all the settings.
+       *
+       * TODO:
+       *   - Instead of having a full sentence "title" for every setting, we
+       *     should have a brief title with an optional "i" on the right side
+       *     that users can click for additional information to pop up (perhaps
+       *     as a Modal?)
+       *   - We shouldn't assume all settings will be ToggleButtonGroup.
+       *     For example, bite initiation settings should instead be checkboxes.
+       */}
+      {/* <Row className='justify-content-center mx-1 my-2'>
+        <Form.Label style={{ fontSize: '30px' }}>Where should the robot wait after it gets food? </Form.Label>
+        <ToggleButtonGroup
+          valueOptions={SETTINGS.stagingPosition}
+          currentValue={useGlobalState((state) => state.stagingPosition)}
+          valueSetter={useGlobalState((state) => state.setStagingPosition)}
+        />
+      </Row>
+
+      <Row className='justify-content-center mx-1 my-2'>
+        <Form.Label style={{ fontSize: '30px' }}>How do you want to indicate readiness for a bite? </Form.Label>
+        <ToggleButtonGroup
+          valueOptions={SETTINGS.biteInitiation}
+          currentValue={useGlobalState((state) => state.biteInitiation)}
+          valueSetter={useGlobalState((state) => state.setBiteInitiation)}
+        />
+      </Row>
+
+      <Row className='justify-content-center mx-1 my-2'>
+        <Form.Label style={{ fontSize: '30px' }}>How do you want to select your desired food item? </Form.Label>
+        <ToggleButtonGroup
+          valueOptions={SETTINGS.biteSelection}
+          currentValue={useGlobalState((state) => state.biteSelection)}
+          valueSetter={useGlobalState((state) => state.setBiteSelection)}
+        />
+      </Row> */}
+    </Container>
+  )
+}
+
+export default Main
diff --git a/feedingwebapp/src/Pages/Settings/Settings.jsx b/feedingwebapp/src/Pages/Settings/Settings.jsx
index b0865e87..c9aa3169 100644
--- a/feedingwebapp/src/Pages/Settings/Settings.jsx
+++ b/feedingwebapp/src/Pages/Settings/Settings.jsx
@@ -1,67 +1,47 @@
 // React imports
-import React from 'react'
-import Row from 'react-bootstrap/Row'
-import Form from 'react-bootstrap/Form'
+import React, { useCallback } from 'react'
+import PropTypes from 'prop-types'
+import { View } from 'react-native'
 
 // Local imports
-import { useGlobalState, SETTINGS } from '../GlobalState'
-import ToggleButtonGroup from '../../buttons/ToggleButtonGroup'
+import { useGlobalState, SETTINGS_STATE } from '../GlobalState'
+import Main from './Main'
+import BiteTransfer from './BiteTransfer'
 
 /**
- * The Settings components displays all the settings users are able to configure.
- * Since settings are stored in global state, options for the settings should be
- * stored in GlobalState.js and this component should primarily focus on
- * rendering them.
+ * The Settings components displays the appropriate settings page based on the
+ * current settings state.
  */
-const Settings = () => {
-  return (
-    <div>
-      {/**
-       * The title of the page.
-       */}
-      <h1 style={{ textAlign: 'center', fontSize: '40px' }} className='txt-huge'>
-        ⚙ Settings
-      </h1>
+const Settings = (props) => {
+  // Get the relevant values from global state
+  const settingsState = useGlobalState((state) => state.settingsState)
+
+  const getComponentBySettingsState = useCallback(() => {
+    console.log('getComponentBySettingsState', settingsState)
+    switch (settingsState) {
+      case SETTINGS_STATE.MAIN:
+        return <Main />
+      case SETTINGS_STATE.BITE_TRANSFER:
+        return <BiteTransfer webrtcURL={props.webrtcURL} />
+      default:
+        console.log('Invalid settings state', settingsState)
+        return <Main />
+    }
+  }, [props.webrtcURL, settingsState])
 
+  // Render the component
+  return (
+    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'start' }}>
       {/**
-       * Load toggle-able buttons for all the settings.
-       *
-       * TODO:
-       *   - Instead of having a full sentence "title" for every setting, we
-       *     should have a brief title with an optional "i" on the right side
-       *     that users can click for additional information to pop up (perhaps
-       *     as a Modal?)
-       *   - We shouldn't assume all settings will be ToggleButtonGroup.
-       *     For example, bite initiation settings should instead be checkboxes.
+       * The main contents of the screen depends on the settingsState.
        */}
-      <Row className='justify-content-center mx-1 my-2'>
-        <Form.Label style={{ fontSize: '30px' }}>Where should the robot wait after it gets food? </Form.Label>
-        <ToggleButtonGroup
-          valueOptions={SETTINGS.stagingPosition}
-          currentValue={useGlobalState((state) => state.stagingPosition)}
-          valueSetter={useGlobalState((state) => state.setStagingPosition)}
-        />
-      </Row>
-
-      <Row className='justify-content-center mx-1 my-2'>
-        <Form.Label style={{ fontSize: '30px' }}>How do you want to indicate readiness for a bite? </Form.Label>
-        <ToggleButtonGroup
-          valueOptions={SETTINGS.biteInitiation}
-          currentValue={useGlobalState((state) => state.biteInitiation)}
-          valueSetter={useGlobalState((state) => state.setBiteInitiation)}
-        />
-      </Row>
-
-      <Row className='justify-content-center mx-1 my-2'>
-        <Form.Label style={{ fontSize: '30px' }}>How do you want to select your desired food item? </Form.Label>
-        <ToggleButtonGroup
-          valueOptions={SETTINGS.biteSelection}
-          currentValue={useGlobalState((state) => state.biteSelection)}
-          valueSetter={useGlobalState((state) => state.setBiteSelection)}
-        />
-      </Row>
-    </div>
+      {getComponentBySettingsState()}
+    </View>
   )
 }
+Settings.propTypes = {
+  // The URL of the webrtc signalling server
+  webrtcURL: PropTypes.string.isRequired
+}
 
 export default Settings
diff --git a/feedingwebapp/src/ros/ros_helpers.js b/feedingwebapp/src/ros/ros_helpers.js
index f94b200a..65c228e8 100644
--- a/feedingwebapp/src/ros/ros_helpers.js
+++ b/feedingwebapp/src/ros/ros_helpers.js
@@ -170,3 +170,35 @@ export function cancelROSAction(actionClient) {
 export function destroyActionClient(actionClient) {
   actionClient.destroyClient()
 }
+
+/**
+ * Takes in an object of type ParameterValue and returns the actual parameter
+ * value. See the message definition for more details:
+ * https://github.com/ros2/rcl_interfaces/blob/rolling/rcl_interfaces/msg/ParameterValue.msg
+ *
+ * @param {object} parameterValue an object of message type ParameterValue
+ */
+export function getParameterValue(parameterValue) {
+  switch (parameterValue.type) {
+    case 1: // bool
+      return parameterValue.bool_value
+    case 2: // integer
+      return parameterValue.integer_value
+    case 3: // double
+      return parameterValue.double_value
+    case 4: // string
+      return parameterValue.string_value
+    case 5: // byte array
+      return parameterValue.byte_array_value
+    case 6: // bool array
+      return parameterValue.bool_array_value
+    case 7: // integer array
+      return parameterValue.integer_array_value
+    case 8: // double array
+      return parameterValue.double_array_value
+    case 9: // string array
+      return parameterValue.string_array_value
+    default: // not set
+      return null
+  }
+}
diff --git a/feedingwebapp/src/webrtc/webrtc_helpers.js b/feedingwebapp/src/webrtc/webrtc_helpers.js
index 4d04959a..bafae5ab 100644
--- a/feedingwebapp/src/webrtc/webrtc_helpers.js
+++ b/feedingwebapp/src/webrtc/webrtc_helpers.js
@@ -4,7 +4,7 @@ import axios from 'axios'
 
 /**
  * Creates a connection to the WebRTC signalling server defined in `server.js`.
- * 
+ *
  * @param {Object} options
  *   @param {string} options.url - The URL of the WebRTC signalling server.
  *   @param {string} options.topic - The topic to subscribe to.
@@ -13,7 +13,7 @@ import axios from 'axios'
  *   @param {string} options.transceiverKind - The kind of transceiver to add to the peer connection.
  *   @param {Object} options.transceiverOptions - The options for the transceiver.
  *   @param {MediaStream} options.stream - The stream to add to the peer connection.
- *  
+ *
  * @returns {WebRTCConnection} The WebRTC connection.
  */
 export class WebRTCConnection {