diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bf16d5a4312e8115ec5a6c46ef82372eec529b4b
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,180 @@
+env:
+  browser: true
+extends: "eslint:recommended"
+rules:
+  # key: 0 = allow, 1 = warn, 2 = error
+
+  # Possible Errors
+  no-await-in-loop: 1
+  no-console: 1
+  no-extra-parens: [1, 'all']
+  no-template-curly-in-string: 0
+
+  # Best Practices
+  accessor-pairs: 0
+  array-callback-return: 0
+  block-scoped-var: 1
+  class-methods-use-this: 0
+  complexity: 0
+  consistent-return: 0
+  curly: [1, 'all']
+  default-case: 1
+  dot-location: [1, 'property']
+  dot-notation: 0
+  eqeqeq: 1
+  guard-for-in: 0
+  max-classes-per-file: 0
+  no-alert: 1
+  no-caller: 1
+  no-div-regex: 1
+  no-else-return: 0
+  no-empty-function: 1
+  no-eq-null: 1
+  no-eval: 0
+  no-extend-native: 0
+  no-extra-bind: 0
+  no-extra-label: 1
+  no-floating-decimal: 1
+  no-implicit-coercion: 1
+  no-implied-eval: 1
+  no-invalid-this: 0
+  no-iterator: 1
+  no-labels: 0
+  no-lone-blocks: 1
+  no-loop-func: 1
+  no-magic-numbers: 0
+  no-multi-spaces: 1
+  no-multi-str: 1
+  no-new: 0
+  no-new-func: 1
+  no-new-wrappers: 1
+  no-octal-escape: 1
+  no-param-reassign: 1
+  no-proto: 1
+  no-restricted-globals: 1
+  no-restricted-properties: 0
+  no-return-assign: 1
+  no-return-await: 1
+  no-script-url: 1
+  no-self-compare: 1
+  no-sequences: 1
+  no-throw-literal: 1
+  no-unmodified-loop-condition: 1
+  no-unused-expressions: 1
+  no-useless-call: 1
+  no-useless-concat: 1
+  no-useless-return: 1
+  no-void: 1
+  no-warning-comments: 0
+  prefer-named-capture-group: 0
+  prefer-promise-reject-errors: 1
+  radix: 1
+  require-await: 1
+  require-unicode-regexp: 0
+  vars-on-top: 1
+  wrap-iife: 1
+  yoda: 1
+
+  # Strict Mode
+  strict: [1, 'safe']
+
+  # Variables
+  init-declarations: 0
+  no-label-var: 1
+  no-implicit-globals: 0
+  no-shadow: 1
+  no-undef-init: 1
+  no-undefined: 1
+  no-use-before-define: 1
+
+  # Stylistic Issues
+  array-bracket-newline: 0
+  array-bracket-spacing: [1, 'never']
+  array-element-newline: 0
+  block-spacing: [1, 'always']
+  brace-style: [1, '1tbs']
+  camelcase: 1
+  capitalized-comments: 0
+  comma-dangle: [1, 'never']
+  comma-spacing: [1, { "before": false, "after": true }]
+  comma-style: 1
+  computed-property-spacing: [1, 'never']
+  consistent-this: [1, 'that']
+  eol-last: 1
+  func-call-spacing: [1, 'never']
+  func-name-matching: [1, 'always']
+  func-names: 0
+  func-style: [1, 'expression']
+  function-paren-newline: [1, 'never']
+  id-blacklist: 0
+  id-length: 0
+  id-match: 0
+  implicit-arrow-linebreak: 0
+  indent: [1, 4]
+  jsx-quotes: 0
+  key-spacing: 1
+  keyword-spacing: 1
+  line-comment-position: [1, 'above']
+  linebreak-style: [1, 'unix']
+  lines-around-comment: 0
+  lines-between-class-members: [1, 'always', { exceptAfterSingleLine: true }]
+  max-depth: [1, 4]
+  max-len: 0
+  max-lines: 0
+  max-lines-per-function: 0
+  max-nested-callbacks: 0
+  max-params: [1, 4]
+  max-statements: 0
+  max-statements-per-line: [1, { max: 1 }]
+  multiline-comment-style: 0
+  multiline-ternary: 0
+  new-cap: 1
+  new-parens: 1
+  newline-per-chained-call: 1
+  no-array-constructor: 0
+  no-bitwise: 0
+  no-continue: 0
+  no-inline-comments: 0
+  no-lonely-if: 1
+  no-mixed-operators: 0
+  no-multi-assign: 1
+  no-multiple-empty-lines: 1
+  no-negated-condition: 0
+  no-nested-ternary: 1
+  no-new-object: 0
+  no-plusplus: 1
+  no-restricted-syntax: 0
+  no-tabs: 1
+  no-ternary: 0
+  no-trailing-spaces: 1
+  no-underscore-dangle: 1
+  no-unneeded-ternary: 1
+  no-whitespace-before-property: 1
+  nonblock-statement-body-position: 1
+  object-curly-newline: 0
+  object-curly-spacing: [1, 'always']
+  object-property-newline: 0
+  one-var: [1, 'consecutive']
+  one-var-declaration-per-line: [1, 'always']
+  operator-assignment: [1, 'always']
+  operator-linebreak: 0
+  padded-blocks: [1, 'never']
+  padding-line-between-statements: 0
+  prefer-object-spread: 0
+  quote-props: 0
+  quotes: [1, 'single']
+  semi: [1, 'always']
+  semi-spacing: [1, { before: false, after: true }]
+  semi-style: [1, 'last']
+  sort-keys: 0
+  sort-vars: 0
+  space-before-blocks: [1, 'always']
+  space-before-function-paren: [1, 'always']
+  space-in-parens: [1, 'never']
+  space-infix-ops: 0
+  space-unary-ops: [1, { words: true, nonwords: false }]
+  spaced-comment: [1, 'always', { markers: ["global", "="] }]
+  switch-colon-spacing: [1, { after: true, before: false }]
+  template-tag-spacing: [1, 'always']
+  unicode-bom: [1, 'never']
+  wrap-regex: 1
diff --git a/.sass-lint.yml b/.sass-lint.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ceb2b87e752e710ef30840bee196fb813dd22f93
--- /dev/null
+++ b/.sass-lint.yml
@@ -0,0 +1,55 @@
+# Linter Options
+options:
+  # Don't merge default rules
+  merge-default-rules: false
+  # Set the formatter to 'html'
+  formatter: html
+  # Output file instead of logging results
+  output-file: 'linters/sass-lint.html'
+  # Raise an error if more than 50 warnings are generated
+  max-warnings: 50
+# File Options
+files:
+  include:
+    - 'app/assets/stylesheets/**/*.s+(a|c)ss'
+    - 'docs/themes/**/*.s+(a|c)ss'
+  ignore:
+    - 'vendor/**/*.*'
+# Rule Configuration
+rules:
+  class-name-format: 0
+  extends-before-mixins: 2
+  extends-before-declarations: 2
+  mixins-before-declarations:
+    - 2
+    -
+      exclude:
+        - breakpoint
+        - breakpoint-next
+        - breakpoint-min
+        - breakpoint-max
+        - breakpoint-infix
+        - media-breakpoint-up
+        - media-breakpoint-down
+        - media-breakpoint-between
+        - media-breakpoint-only
+        - mq
+  no-warn: 1
+  no-debug: 1
+  hex-length:
+    - 2
+    -
+      style: long
+  hex-notation:
+    - 2
+    -
+      style: uppercase
+  indentation:
+    - 4
+    -
+      size: 4
+  property-sort-order:
+    - 1
+    -
+      order: alphabetical
+      ignore-custom-properties: false
diff --git a/app/assets/stylesheets/application.sass b/app/assets/stylesheets/application.sass
index d5b57dee4e5a818ccd0fcc9f51e1ecd835196811..27474b5d81f82f89fc5c67af09b5b7241062c228 100644
--- a/app/assets/stylesheets/application.sass
+++ b/app/assets/stylesheets/application.sass
@@ -1,2 +1,4 @@
-@import "bootstrap"
+@import 'bootstrap'
+@import 'appstack/light'
+@import 'simple_form_password_with_hints'
 @import 'application/*'
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb
index db3f81f6a1f0c04e0035b8f34a9b589d50af909a..4620a2382b6ee35724c3ecf3e259c21a2f1a8f47 100644
--- a/app/views/devise/sessions/new.html.erb
+++ b/app/views/devise/sessions/new.html.erb
@@ -1,20 +1,32 @@
-<h2><%= t(".sign_in") %></h2>
+<h2 class="text-center"><%= t('login.not_registered_yet') %></h2>
+<div class="form-actions text-center mt-3">
+  <%= link_to t("devise.registrations.new.sign_up"), new_registration_path(resource_name), class: 'btn btn btn-lg btn-primary' %><br />
+</div>
 
+<hr class="mt-4 mb-4">
+
+<h2 class="text-center"><%= t('login.already_registered') %></h2>
 <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
   <div class="form-inputs">
     <%= f.input :email,
                 required: false,
                 autofocus: true,
                 input_html: { autocomplete: "email" } %>
-    <%= f.input :password,
-                as: :password_with_hints,
-                allow_password_uncloaking: true,
-                required: false,
-                input_html: { autocomplete: "current-password" } %>
+    <div class="mb-3 password optional user_password">
+      <%= f.input :password,
+                  as: :password_with_hints,
+                  allow_password_uncloaking: true,
+                  required: false,
+                  wrapper: false,
+                  input_html: { autocomplete: "current-password" } %>
+      <small>
+        <%= link_to t("devise.passwords.new.forgot_your_password"), new_password_path(resource_name) %>
+      </small>
+    </div>
     <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %>
   </div>
 
-  <div class="form-actions">
+  <div class="form-actions text-center mt-3">
     <%= f.button :submit, t(".sign_in"), class: 'btn btn-lg btn-primary' %>
   </div>
 <% end %>
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb
index d11c0611c870c0746348378fa6beedcde1025938..05579cd5c218fad2ef7dd3e8e59733b2e0283b5f 100644
--- a/app/views/devise/shared/_links.html.erb
+++ b/app/views/devise/shared/_links.html.erb
@@ -1,25 +1,19 @@
-<%- if controller_name != 'sessions' %>
-  <%= link_to t(".sign_in"), new_session_path(resource_name) %><br />
-<% end %>
-
-<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
-  <%= link_to t(".sign_up"), new_registration_path(resource_name) %><br />
-<% end %>
-
-<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
-  <%= link_to t(".forgot_your_password"), new_password_path(resource_name) %><br />
-<% end %>
+<div class="text-center mt-2">
+  <%- if controller_name != 'sessions' %>
+    <%= link_to t(".sign_in"), new_session_path(resource_name) %><br />
+  <% end %>
 
-<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
-  <%= link_to t('.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name) %><br />
-<% end %>
+  <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
+    <%= link_to t('.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name) %><br />
+  <% end %>
 
-<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
-  <%= link_to t('.didn_t_receive_unlock_instructions'), new_unlock_path(resource_name) %><br />
-<% end %>
+  <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
+    <%= link_to t('.didn_t_receive_unlock_instructions'), new_unlock_path(resource_name) %><br />
+  <% end %>
 
-<%- if devise_mapping.omniauthable? %>
-  <%- resource_class.omniauth_providers.each do |provider| %>
-    <%= link_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), omniauth_authorize_path(resource_name, provider), method: :post %><br />
+  <%- if devise_mapping.omniauthable? %>
+    <%- resource_class.omniauth_providers.each do |provider| %>
+      <%= link_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), omniauth_authorize_path(resource_name, provider), method: :post %><br />
+    <% end %>
   <% end %>
-<% end %>
+</div>
diff --git a/app/views/layouts/devise.html.erb b/app/views/layouts/devise.html.erb
index bf0769f907de1d36782224e0efe78ae5031eb4c6..834a33ea7f010d50a6eb4ccbcc65f8bc84ccb782 100644
--- a/app/views/layouts/devise.html.erb
+++ b/app/views/layouts/devise.html.erb
@@ -6,8 +6,8 @@
     <title><%= yield :title %></title>
     <%= csrf_meta_tags %>
     <%= csp_meta_tag %>
-    <%= stylesheet_link_tag 'admin', media: 'all' %>
-    <%= javascript_include_tag 'admin' %>
+    <%= stylesheet_link_tag 'application', media: 'all' %>
+    <%= javascript_include_tag 'application' %>
     <%= favicon_link_tag 'favicon.png' %>
   </head>
   <body data-theme="default" data-layout="fluid">
@@ -17,7 +17,12 @@
           <div class="row h-100">
             <div class="col-sm-10 col-md-8 col-lg-6 mx-auto d-table h-100">
               <div class="d-table-cell align-middle">
-                <h1 class="mb-5 text-center"><%= current_university %></h1>
+                <div class="text-center mt-4">
+                  <h1 class="h2"><%= current_university %></h1>
+                  <p class="lead">
+  									<%= t('login.subtitle') %>
+  								</p>
+                </div>
                 <div class="card">
                   <div class="card-body text-start">
                     <div class="m-sm-4">
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 1d3a8099e197f91a9526300a883a1ec7599c36c6..941e35100b4bbe64ac48699ccabe25db28b5e005 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1,63 +1,66 @@
 en:
-  true: Yes
-  false: No
-  home: Home
-  dashboard: Dashboard
-  show: Show
-  create: Create
-  edit: Edit
-  delete: Delete
-  please-confirm: Are you sure?
-  validate: Validate
   activerecord:
     models:
       university:
+        language:
+          one: Language
+          other: Languages
+          user:
+            attributes:
+              university:
+                address: Address
+                city: City
+                country: Country
+                name: Name
+                private: Private
+                public: Public
+                public_or_private: Public/private
+                zipcode: Zipcode
+                user:
+                  email: Email
+                  first_name: First name
+                  language: Favourite language
+                  last_name: Last name
+                  mobile_phone: Mobile phone
+                  researcher: Researcher profile
+                  role: Role
+            one: User
+            other: Users
         one: University
         other: Universities
-      language:
-        one: Language
-        other: Languages
-      user:
-        one: User
-        other: Users
-    attributes:
-      university:
-        name: Name
-        address: Address
-        zipcode: Zipcode
-        city: City
-        country: Country
-        private: Private
-        public_or_private: Public/private
-        public: Public
-        private: Private
-      user:
-        email: Email
-        first_name: First name
-        last_name: Last name
-        mobile_phone: Mobile phone
-        role: Role
-        researcher: Researcher profile
-        language: Favourite language
+  create: Create
+  dashboard: Dashboard
+  delete: Delete
   devise:
     mailer:
       two_factor_authentication:
         subject: "Two-factor authentication code"
+        shared:
+          links:
+            sign_out: "Sign out"
+            two_factor_authentication:
+              attempt_failed: "Invalid Code"
+              code_has_been_sent: "Your authentication code has been sent."
+              enter_code_direct_otp: "Enter the code that was sent to you"
+              enter_code_totp: "Enter the code from your authentication application"
+              max_login_attempts_reached: "You're account has been locked for security reasons.<br />Please contact an administrator."
+              resend_code: "Resend Code"
+              send_code_instead: "Send me a code instead"
+              send_email_code: 'Send me a code via email'
+              success: ""
         text_html: "Your two-factor authentication code for %{university} is %{code}<br>It will expire in 5 minutes."
-    shared:
-      links:
-        sign_out: "Sign out"
-    two_factor_authentication:
-      attempt_failed: "Invalid Code"
-      code_has_been_sent: "Your authentication code has been sent."
-      enter_code_direct_otp: "Enter the code that was sent to you"
-      enter_code_totp: "Enter the code from your authentication application"
-      max_login_attempts_reached: "You're account has been locked for security reasons.<br />Please contact an administrator."
-      resend_code: "Resend Code"
-      send_code_instead: "Send me a code instead"
-      send_email_code: 'Send me a code via email'
-      success: ""
+  edit: Edit
+  false: No
+  home: Home
+  login:
+    already_registered: Already registered?
+    not_registered_yet: Not registered yet?
+    subtitle: Sign in to your account to continue
+  please-confirm: Are you sure?
   simple_form:
     hints:
       user:
-        mobile_phone: "International format (+XX)"
\ No newline at end of file
+        mobile_phone: "International format (+XX)"
+  show: Show
+  true: Yes
+  validate: Validate
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 6c9359b576911889f88980fe9d1382908985edbd..0758a3567f8e9fc8c8fc6649a3f2c56c7542c568 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -1,63 +1,66 @@
 fr:
-  true: Oui
-  false: Non
-  home: Accueil
-  dashboard: Tableau de bord
-  show: Voir
-  create: Créer
-  edit: Modifier
-  delete: Supprimer
-  please-confirm: Est-ce que vous confirmez ?
-  validate: Valider
   activerecord:
     models:
       university:
+        language:
+          one: Langue
+          other: Langues
+          user:
+            attributes:
+              university:
+                address: Adresse
+                city: Ville
+                country: Pays
+                name: Nom
+                private: Etablissement privé
+                public: Public
+                public_or_private: Public/privé
+                user:
+                  email: Email
+                  first_name: Prénom
+                  language: Langue préférée
+                  last_name: Nom
+                  mobile_phone: Téléphone portable
+                  researcher: Profil de chercheur
+                  role: Rôle
+                zipcode: Code postal
+            one: Utilisateur
+            other: Utilisateurs
         one: Université
         other: Universités
-      language:
-        one: Langue
-        other: Langues
-      user:
-        one: Utilisateur
-        other: Utilisateurs
-    attributes:
-      university:
-        name: Nom
-        address: Adresse
-        zipcode: Code postal
-        city: Ville
-        country: Pays
-        private: Etablissement privé
-        public_or_private: Public/privé
-        public: Public
-        private: Privé
-      user:
-        email: Email
-        first_name: Prénom
-        last_name: Nom
-        mobile_phone: Téléphone portable
-        role: Rôle
-        researcher: Profil de chercheur
-        language: Langue préférée
+  create: Créer
+  dashboard: Tableau de bord
+  delete: Supprimer
   devise:
     mailer:
       two_factor_authentication_code:
         subject: "Code d'authentification à deux facteurs"
+        shared:
+          links:
+            sign_out: "Se déconnecter"
+            two_factor_authentication:
+              attempt_failed: "Code invalide"
+              code_has_been_sent: "Un code d'authentification vient de vous être envoyé."
+              enter_code_direct_otp: "Entrez le code qui vous a été envoyé"
+              enter_code_totp: "Entrez le code de votre application d'authentification"
+              max_login_attempts_reached: "Votre compte a été bloqué pour des raisons de sécurité.<br />Veuillez contacter un administrateur."
+              resend_code: "Renvoyer le code"
+              send_code_instead: "Envoyez-moi plutôt un code"
+              send_email_code: 'Envoyer le code par email'
+              success: ""
         text_html: "Votre code d'authentification pour %{university} est %{code}<br>Il expirera dans 5 minutes."
-    shared:
-      links:
-        sign_out: "Se déconnecter"
-    two_factor_authentication:
-      attempt_failed: "Code invalide"
-      code_has_been_sent: "Un code d'authentification vient de vous être envoyé."
-      enter_code_direct_otp: "Entrez le code qui vous a été envoyé"
-      enter_code_totp: "Entrez le code de votre application d'authentification"
-      max_login_attempts_reached: "Votre compte a été bloqué pour des raisons de sécurité.<br />Veuillez contacter un administrateur."
-      resend_code: "Renvoyer le code"
-      send_code_instead: "Envoyez-moi plutôt un code"
-      send_email_code: 'Envoyer le code par email'
-      success: ""
+  edit: Modifier
+  false: Non
+  home: Accueil
+  login:
+    already_registered: Déjà inscrit ?
+    not_registered_yet: Pas encore inscrit ?
+    subtitle: Vous devez être authentifié pour continuer
+  please-confirm: Est-ce que vous confirmez ?
   simple_form:
     hints:
       user:
-        mobile_phone: "Format international (+XX)"
\ No newline at end of file
+        mobile_phone: "Format international (+XX)"
+  show: Voir
+  true: Oui
+  validate: Valider