Membership: UI Rework

Change-Id: I8d1da12fd764972dc810846afd70760bdb450fe8
diff --git a/core/auth/memberships/main.go b/core/auth/memberships/main.go
index 20f08ef..808d5a8 100644
--- a/core/auth/memberships/main.go
+++ b/core/auth/memberships/main.go
@@ -124,7 +124,7 @@
 		return err
 	}
 	if count != 0 {
-		return fmt.Errorf("store already initialised")
+		return fmt.Errorf("Store already initialised")
 	}
 	for _, g := range groups {
 		query := `INSERT INTO groups (name, description) VALUES (?, '')`
@@ -289,21 +289,21 @@
 
 func (s *SQLiteStore) AddChildGroup(parent, child string) error {
 	if parent == child {
-		return fmt.Errorf("parent and child groups can not have same name")
+		return fmt.Errorf("Parent and child groups can not have same name")
 	}
 	exists, err := s.DoesGroupExist(parent)
 	if err != nil {
-		return fmt.Errorf("error checking parent group existence: %v", err)
+		return fmt.Errorf("Error checking parent group existence: %v", err)
 	}
 	if !exists {
-		return fmt.Errorf("parent group with name %s does not exist", parent)
+		return fmt.Errorf("Parent group with name %s does not exist", parent)
 	}
 	exists, err = s.DoesGroupExist(child)
 	if err != nil {
-		return fmt.Errorf("error checking child group existence: %v", err)
+		return fmt.Errorf("Error checking child group existence: %v", err)
 	}
 	if !exists {
-		return fmt.Errorf("child group with name %s does not exist", child)
+		return fmt.Errorf("Child group with name %s does not exist", child)
 	}
 	parentGroups, err := s.GetAllTransitiveGroupsForGroup(parent)
 	if err != nil {
@@ -311,14 +311,14 @@
 	}
 	for _, group := range parentGroups {
 		if group.Name == child {
-			return fmt.Errorf("circular reference detected: group %s is already a parent of group %s", child, parent)
+			return fmt.Errorf("Circular reference detected: group %s is already a parent of group %s", child, parent)
 		}
 	}
 	_, err = s.db.Exec(`INSERT INTO group_to_group (parent_group, child_group) VALUES (?, ?)`, parent, child)
 	if err != nil {
 		sqliteErr, ok := err.(*sqlite3.Error)
 		if ok && sqliteErr.ExtendedCode() == ErrorUniqueConstraintViolation {
-			return fmt.Errorf("child group name %s already exists in group %s", child, parent)
+			return fmt.Errorf("Child group name %s already exists in group %s", child, parent)
 		}
 		return err
 	}
@@ -426,7 +426,7 @@
 		return err
 	}
 	if rowDeletedNumber == 0 {
-		return fmt.Errorf("pair of parent '%s' and child '%s' groups not found", parent, child)
+		return fmt.Errorf("Pair of parent '%s' and child '%s' groups not found", parent, child)
 	}
 	return nil
 }
@@ -438,7 +438,7 @@
 			return err
 		}
 		if len(owners) == 1 {
-			return fmt.Errorf("cannot remove the last owner of the group")
+			return fmt.Errorf("Cannot remove the last owner of the group")
 		}
 	}
 	query := fmt.Sprintf("DELETE FROM %s WHERE username = ? AND group_name = ?", tableName)
@@ -451,34 +451,34 @@
 		return err
 	}
 	if rowDeletedNumber == 0 {
-		return fmt.Errorf("pair of group '%s' and user '%s' not found", groupName, username)
+		return fmt.Errorf("Pair of group '%s' and user '%s' not found", groupName, username)
 	}
 	return nil
 }
 
 func (s *SQLiteStore) AddOwnerGroup(owner_group, owned_group string) error {
 	if owned_group == owner_group {
-		return fmt.Errorf("group can not own itself")
+		return fmt.Errorf("Group can not own itself")
 	}
 	exists, err := s.DoesGroupExist(owned_group)
 	if err != nil {
-		return fmt.Errorf("error checking owned group existence: %v", err)
+		return fmt.Errorf("Error checking owned group existence: %v", err)
 	}
 	if !exists {
-		return fmt.Errorf("owned group with name %s does not exist", owned_group)
+		return fmt.Errorf("Owned group with name %s does not exist", owned_group)
 	}
 	exists, err = s.DoesGroupExist(owner_group)
 	if err != nil {
-		return fmt.Errorf("error checking owner group existence: %v", err)
+		return fmt.Errorf("Error checking owner group existence: %v", err)
 	}
 	if !exists {
-		return fmt.Errorf("owner group with name %s does not exist", owner_group)
+		return fmt.Errorf("Owner group with name %s does not exist", owner_group)
 	}
 	_, err = s.db.Exec(`INSERT INTO owner_groups (owner_group, owned_group) VALUES (?, ?)`, owner_group, owned_group)
 	if err != nil {
 		sqliteErr, ok := err.(*sqlite3.Error)
 		if ok && sqliteErr.ExtendedCode() == ErrorUniqueConstraintViolation {
-			return fmt.Errorf("group named %s is already owner of a group %s", owner_group, owned_group)
+			return fmt.Errorf("Group named %s is already owner of a group %s", owner_group, owned_group)
 		}
 		return err
 	}
@@ -519,6 +519,7 @@
 	} else {
 		return "", fmt.Errorf("unauthenticated")
 	}
+	// return "user", nil
 }
 
 type Status int
@@ -573,7 +574,7 @@
 		return err
 	}
 	if !isMemberOfOwnerGroup {
-		return fmt.Errorf("you are not the owner or a member of any owner group of the group %s", group)
+		return fmt.Errorf("You are not the owner or a member of any owner group of the group %s", group)
 	}
 	return nil
 }
@@ -1057,11 +1058,11 @@
 
 func isValidGroupName(group string) error {
 	if strings.TrimSpace(group) == "" {
-		return fmt.Errorf("group name can't be empty or contain only whitespaces")
+		return fmt.Errorf("Group name can't be empty or contain only whitespaces")
 	}
 	validGroupName := regexp.MustCompile(`^[a-z0-9\-_:.\/ ]+$`)
 	if !validGroupName.MatchString(group) {
-		return fmt.Errorf("group name should contain only lowercase letters, digits, -, _, :, ., /")
+		return fmt.Errorf("Group name should contain only lowercase letters, digits, -, _, :, ., /")
 	}
 	return nil
 }
diff --git a/core/auth/memberships/memberships-tmpl/base.html b/core/auth/memberships/memberships-tmpl/base.html
index 39a7755..50b792e 100644
--- a/core/auth/memberships/memberships-tmpl/base.html
+++ b/core/auth/memberships/memberships-tmpl/base.html
@@ -5,7 +5,7 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>{{ block "title" . }}{{ end }}</title>
     <link rel="stylesheet" href="/static/pico.2.0.6.min.css">
-    <link rel="stylesheet" href="/static/main.css">
+    <link rel="stylesheet" href="/static/main.css?v=0.0.1">
 </head>
 <body class="container">
     {{- block "content" . }}
@@ -13,7 +13,7 @@
     {{ if ne .ErrorMessage "" }}
     <dialog id="error-message" open>
         <article>
-            <h2>Error</h2>
+            <h3>Error</h3>
             <p id="error-message-content">{{ .ErrorMessage }}</p>
             <footer>
                 <button id="error-cancel-button" class="secondary error-cancel-button">Close</button>
diff --git a/core/auth/memberships/memberships-tmpl/group.html b/core/auth/memberships/memberships-tmpl/group.html
index 46f833f..4576a92 100644
--- a/core/auth/memberships/memberships-tmpl/group.html
+++ b/core/auth/memberships/memberships-tmpl/group.html
@@ -1,125 +1,133 @@
+{{ define "svgIcon" }}
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+    <g fill="none" fill-rule="evenodd">
+        <path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
+        <path fill="currentColor" d="m12 13.414l5.657 5.657a1 1 0 0 0 1.414-1.414L13.414 12l5.657-5.657a1 1 0 0 0-1.414-1.414L12 10.586L6.343 4.929A1 1 0 0 0 4.93 6.343L10.586 12l-5.657 5.657a1 1 0 1 0 1.414 1.414z" />
+    </g>
+</svg>
+{{ end }}
+
 {{ define "title" }}
     Group - {{ .GroupName }}
 {{ end }}
+
 {{ define "content" }}
 {{- $parentGroupName := .GroupName }}
     <div>
-        <h2 class="headline">{{ .GroupName }} Group Management</h2>
+        <h2 class="headline">Group: {{ .GroupName }}</h2>
         <p class="description">{{ .Description }}</p>
     </div>
     <hr class="divider">
     <form action="/group/{{ .GroupName }}/add-user/" method="post">
-        <label>Username:</label>
-        <input type="text" id="username" name="username" required>
-        <label for="status">Status:</label>
-        <select id="status" name="status" required>
-            <option value="Member" selected>Member</option>
-            <option value="Owner">Owner</option>
-        </select>
-        <button type="submit">Add Member</button>
+        <fieldset class="grid first">
+            <input type="text" id="username" name="username" placeholder="username" required>
+            <select id="status" name="status" required>
+                <option value="Member" selected>Member</option>
+                <option value="Owner">Owner</option>
+            </select>
+            <button type="submit">Add Member</button>
+        </fieldset>
     </form>
-    <hr class="divider">
     <form action="/group/{{ .GroupName }}/add-child-group" method="post">
-        <label for="child-group">Select Child Group:</label>
-        <select id="child-group" aria-label="Select" name="child-group" required>
-            {{- range .AllGroups }}
-            <option value="{{ .Name }}">{{ .Name }}</option>
-            {{- end }}
-        </select>
-        <button type="submit">Create Child Group</button>
+        <fieldset class="grid twoone">
+            <select id="child-group" aria-label="Select" name="child-group" required>
+                {{- range .AllGroups }}
+                <option value="{{ .Name }}">{{ .Name }}</option>
+                {{- end }}
+            </select>
+            <button type="submit">Create Child Group</button>
+        </fieldset>
+    </form>
+    <form action="/group/{{ .GroupName }}/add-owner-group" method="post">
+        <fieldset class="grid twoone">
+            <select id="owner-group" aria-label="Select" name="owner-group" required>
+                {{- range .AllGroups }}
+                <option value="{{ .Name }}">{{ .Name }}</option>
+                {{- end }}
+            </select>
+            <button type="submit">Add Owner Group</button>
+        </fieldset>
     </form>
     <hr class="divider">
-    <form action="/group/{{ .GroupName }}/add-owner-group" method="post">
-        <label for="owner-group">Select Owner Group:</label>
-        <select id="owner-group" aria-label="Select" name="owner-group" required>
-            {{- range .AllGroups }}
-            <option value="{{ .Name }}">{{ .Name }}</option>
-            {{- end }}
-        </select>
-        <button type="submit">Add Owner Group</button>
-    </form>
-    <h4>Owners</h4>
-    <table>
-        <tr>
-            <th>Username</th>
-            <th>Action</th>
-        </tr>
+    <h3>Owners</h3>
+    <div class="user-remove">
         {{- range .Owners }}
-        <tr>
-            <td><a href="/user/{{ . }}">{{ . }}</a></td>
-            <td>
-                <form action="/group/{{ $parentGroupName }}/remove-owner/{{ . }}" method="post" class="remove-form" data-confirmation-message="Are you sure you want to revoke user <strong>{{ . }}</strong>'s ownership of the  <strong>{{ $parentGroupName }}</strong> group?">
-                    <button type="submit">Remove</button>
-                </form>
-            </td>
-        </tr>
+        <div>
+            <fieldset role="group">
+            <a class="link-button" href="/user/{{ . }}" role="button">{{ . }}</a>
+            <form action="/group/{{ $parentGroupName }}/remove-owner/{{ . }}" method="post" class="remove-form" data-confirmation-message="Are you sure you want to revoke user <strong>{{ . }}</strong>'s ownership of the  <strong>{{ $parentGroupName }}</strong> group?">
+                <button class="remove" type="submit" aria-label="Remove owner">
+                    {{ template "svgIcon" }}
+                </button>
+            </form>
+            </fieldset>
+        </div>
         {{- end }}
-    </table>
-    <h4>Members</h4>
-    <table>
-        <tr>
-            <th>Username</th>
-            <th>Action</th>
-        </tr>
+    </div>
+    
+    <hr class="divider">
+
+    <h3>Members</h3>
+    <div class="user-remove">
         {{- range .Members }}
-        <tr>
-            <td><a href="/user/{{ . }}">{{ . }}</a></td>
-            <td>
-                <form action="/group/{{ $parentGroupName }}/remove-member/{{ . }}" method="post" class="remove-form" data-confirmation-message="Are you sure you want to remove user  <strong>{{ . }}</strong> user from  <strong>{{ $parentGroupName }}</strong> group?">
-                    <button type="submit" class="button">Remove</button>
-                </form>
-            </td>
-        </tr>
+        <div>
+            <fieldset role="group">
+                <a class="link-button" href="/user/{{ . }}" role="button">{{ . }}</a>
+            <form action="/group/{{ $parentGroupName }}/remove-member/{{ . }}" method="post" class="remove-form" data-confirmation-message="Are you sure you want to remove user  <strong>{{ . }}</strong> user from  <strong>{{ $parentGroupName }}</strong> group?">
+                <button class="remove" type="submit">
+                    {{ template "svgIcon" }}
+                </button>
+            </form>
+            </fieldset>
+        </div>
         {{- end }}
-    </table>
-    <h4>Transitive Groups</h4>
-    <table>
-        <tr>
-            <th>Group Name</th>
-            <th>Description</th>
-        </tr>
+    </div>
+    <hr class="divider">
+
+    <h3>Transitive Groups</h3>
+    <div class="user-remove">
         {{- range .TransitiveGroups }}
-        <tr>
-            <td><a href="/group/{{ .Name }}">{{ .Name }}</a></td>
-            <td>{{ .Description }}</td>
-        </tr>
+            <a class="link-button" href="/group/{{ .Name }}" role="button" 
+               {{ if ne .Description "" }} data-tooltip="{{ .Description }}" data-placement="bottom" {{ end }}>
+               {{ .Name }}
+            </a>
         {{- end }}
-    </table>
-    <h4>Child Groups</h4>
-    <table>
-        <tr>
-            <th>Group Name</th>
-            <th>Description</th>
-            <th>Action</th>
-        </tr>
+    </div>
+    <hr class="divider">
+
+    <h3>Child Groups</h3>
+    <div class="user-remove">
         {{- range .ChildGroups }}
-        <tr>
-            <td><a href="/group/{{ .Name }}">{{ .Name }}</a></td>
-            <td>{{ .Description }}</td>
-            <td>
+        <div>
+            <fieldset role="group">
+                <a class="link-button" href="/group/{{ .Name }}" role="button" 
+                    {{ if ne .Description "" }} data-tooltip="{{ .Description }}" data-placement="bottom" {{ end }}>
+                    {{ .Name }}
+                </a>
                 <form action="/group/{{ $parentGroupName }}/remove-child-group/{{ .Name }}" method="post" class="remove-form" data-confirmation-message="Are you sure you want to remove group  <strong>{{ .Name }}</strong> as a child of the group  <strong>{{ $parentGroupName }}</strong>?">
-                    <button type="submit" class="button">Remove</button>
+                    <button class="remove" type="submit">
+                        {{ template "svgIcon" }}
+                    </button>
                 </form>
-            </td>
-        </tr>
+            </fieldset>
+        </div>
         {{- end }}
-    </table>
-    <h4>Owner Groups</h4>
-    <table>
-        <tr>
-            <th>Group Name</th>
-            <th>Description</th>
-        </tr>
+    </div>
+    <hr class="divider">
+
+    <h3>Owner Groups</h3>
+    <div class="user-remove">
         {{- range .OwnerGroups }}
-        <tr>
-            <td><a href="/group/{{ .Name }}">{{ .Name }}</a></td>
-            <td>{{ .Description }}</td>
-        </tr>
+        <a class="link-button" href="/group/{{ .Name }}" role="button" 
+            {{ if ne .Description "" }} data-tooltip="{{ .Description }}" data-placement="bottom" {{ end }}>
+            {{ .Name }}
+        </a>
         {{- end }}
-    </table>
+    </div>
+
     <dialog id="confirmation" close>
         <article>
-            <h2>Confirm Your Action</h2>
+            <h3>Attention</h3>
             <p id="confirmation-message">Are you sure?</p>
             <footer>
                 <button id="cancel-button" class="secondary cancel-button">Cancel</button>
diff --git a/core/auth/memberships/memberships-tmpl/user.html b/core/auth/memberships/memberships-tmpl/user.html
index 53a89be..4d52092 100644
--- a/core/auth/memberships/memberships-tmpl/user.html
+++ b/core/auth/memberships/memberships-tmpl/user.html
@@ -2,53 +2,46 @@
     User - {{ .CurrentUser }}
 {{ end }}
 {{- define "content" -}}
-    <h1>User: {{ .CurrentUser }}</h1>
+    <h1 class="headline">User: {{ .CurrentUser }}</h1>
     {{ if .LoggedInUserPage }}
     <form action="/create-group" method="post">
-        <label for="group-name">Group Name:</label>
-        <input type="text" id="group-name" name="group-name" required>
-        <label for="description">Group Description:</label>
-        <input type="text" id="description" name="description">
-        <button type="submit">Create Group</button>
+        <fieldset class="grid first">
+            <input type="text" id="group-name" name="group-name" placeholder="Group name" required>
+            <input type="text" id="description" name="description" placeholder="Description">
+            <button type="submit">Create Group</button>
+        </fieldset>
     </form>
     {{ end }}
-    <h4>Owner</h4>
-    <table>
-        <tr>
-            <th>Name</th>
-            <th>Description</th>
-        </tr>
-        {{- range .OwnerGroups -}}
-        <tr>
-            <td><a href="/group/{{ .Name }}">{{ .Name }}</a></td>
-            <td>{{ .Description }}</td>
-        </tr>
-        {{- end -}}
-    </table>
-    <h4>Member</h4>
-    <table>
-        <tr>
-            <th>Name</th>
-            <th>Description</th>
-        </tr>
-        {{- range .MembershipGroups -}}
-        <tr>
-            <td><a href="/group/{{ .Name }}">{{ .Name }}</a></td>
-            <td>{{ .Description }}</td>
-        </tr>
-        {{- end -}}
-    </table>
-    <h4>Transitive Groups</h4>
-    <table>
-        <tr>
-            <th>Name</th>
-            <th>Description</th>
-        </tr>
+
+    <h3>Owner of groups</h3>
+    <div class="user-remove">
+        {{- range .OwnerGroups }}
+            <a href="/group/{{ .Name }}" role="button" 
+                {{ if ne .Description "" }} data-tooltip="{{ .Description }}" data-placement="bottom" {{ end }}>
+                {{ .Name }}
+            </a>
+        {{- end }}
+    </div>
+    <hr class="divider">
+
+    <h3>Direct member of groups</h3>
+    <div class="user-remove">
+        {{- range .MembershipGroups }}
+            <a href="/group/{{ .Name }}" role="button" 
+                {{ if ne .Description "" }} data-tooltip="{{ .Description }}" data-placement="bottom" {{ end }}>
+                {{ .Name }}
+            </a>
+        {{- end }}
+    </div>
+    <hr class="divider">
+
+    <h3>Transitive member of groups</h3>
+    <div class="user-remove">
         {{- range .TransitiveGroups -}}
-        <tr>
-            <td><a href="/group/{{ .Name }}">{{ .Name }}</a></td>
-            <td>{{ .Description }}</td>
-        </tr>
-        {{- end -}}
-    </table>
+            <a href="/group/{{ .Name }}" role="button" 
+               {{ if ne .Description "" }} data-tooltip="{{ .Description }}" data-placement="bottom" {{ end }}>
+               {{ .Name }}
+            </a>
+        {{- end }}
+    </div>
 {{- end }}
diff --git a/core/auth/memberships/static/main.css b/core/auth/memberships/static/main.css
index 7d4e759..17c09f8 100644
--- a/core/auth/memberships/static/main.css
+++ b/core/auth/memberships/static/main.css
@@ -1,13 +1,142 @@
-.headline {
-    margin-bottom: 6px;
+[data-theme="light"],
+:root:not([data-theme="dark"]) {
+  --pico-font-family: Hack, monospace;
+  --pico-font-size: 14px;
+  --pico-header-height: 56px;
+  --pico-border-radius: 0;
+  --pico-background-color: #d6d6d6;
+  --pico-form-element-border-color: #3a3a3a;
+  --pico-form-element-active-border-color: #7f9f7f;
+  --pico-form-element-focus-color: #7f9f7f;
+  --pico-form-element-background-color: #d6d6d6;
+  --pico-form-element-active-background-color: #d6d6d6;
+  --pico-form-element-selected-background-color: #d6d6d6;
+  --pico-primary: #7f9f7f;
+  --pico-primary-background: #7f9f7f;
+  --pico-primary-hover: #d4888d;
+  --pico-primary-hover-background: #d4888d;
+  --pico-grid-spacing-horizontal: 0;
+  --search-background-color: #d6d6d6;
+  --pico-color: #3a3a3a;
+  --pico-form-element-color: #3a3a3a;
+  --pico-primary-inverse: #3a3a3a;
+  --pico-tooltip-background-color: #3a3a3a;
+  --pico-tooltip-color: #d6d6d6;
+  --pico-icon-color: #3a3a3a;
+  --pico-group-box-shadow-focus-with-button: 0 0 0 0;
+  --pico-card-background-color: var(--pico-card-sectioning-background-color);
+  p {
+    --pico-color: #3a3a3a;
+  }
+  h1 {
+    font-size: 20px;
+    --pico-color: #3a3a3a;
+  }
+  h2 {
+    font-size: 18px;
+    --pico-color: #3a3a3a;
+  }
+  h3 {
+    font-size: 16px;
+    --pico-color: #3a3a3a;
+  }
+  h4 {
+    font-size: 14px;
+    --pico-color: #3a3a3a;
+  }
+  label {
+    color: var(--pico-color);
+  }
+  input:is([type="checkbox"]) {
+    --pico-form-element-focus-color: none;
+    --pico-border-color: var(--pico-color);
+  }
+  [data-tooltip]:not(a, button, input) {
+    text-decoration: none;
+    cursor: pointer;
+  }
+  hr {
+    border-top: 1px solid var(--pico-color);
+  }
+  :is(button, [type="submit"], [type="button"], [role="button"]).secondary,
+  [type="file"]::file-selector-button,
+  [type="reset"] {
+    --pico-background-color: var(--pico-primary-hover-background);
+    --pico-border-color: var(--pico-primary-hover);
+    --pico-color: var(--pico-color);
+    cursor: pointer;
+  }
+  #confirm-button:hover {
+    background-color: var(--pico-primary);
+    border-color: var(--pico-primary);
+  }
 }
 
-.description {
-    margin-left: 1px;
-    margin-bottom: 6px;
+@media (min-width: 768px) {
+  .grid.first {
+    grid-template-columns: 1fr 1fr 200px;
+  }
+
+  .grid.twoone {
+    grid-template-columns: 2fr 200px;
+    align-items: center;
+    grid-row-gap: 0;
+  }
+}
+
+.grid-header,
+.grid-row {
+  display: contents;
+}
+
+.headline {
+  margin-top: 15px;
 }
 
 .divider {
-    margin-top: 10px;
-    margin-bottom: 10px;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+
+.remove {
+  margin-bottom: 0;
+  background-color: var(--pico-primary-hover);
+  /* border-top-right-radius: 0.25rem;
+  border-bottom-right-radius: 0.25rem; */
+  border: none;
+  outline: none;
+  padding: 0;
+  height: 100%;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.remove svg {
+  height: 20px;
+  width: 20px;
+}
+
+.test {
+  margin-right: 3rem;
+}
+
+.link-button {
+  /* border-top-left-radius: 0.25rem;
+  border-bottom-left-radius: 0.25rem; */
+}
+
+.user-remove {
+  display: flex;
+  flex-direction: row;
+  gap: 5px;
+  flex-wrap: wrap;
+}
+
+a[role="button"],
+a[role="button"]:hover,
+a[role="button"]:focus {
+  background-color: var(--pico-primary);
+  border: none;
+  outline: none;
 }
diff --git a/core/auth/memberships/static/main.js b/core/auth/memberships/static/main.js
index 52dd1d8..ba58654 100644
--- a/core/auth/memberships/static/main.js
+++ b/core/auth/memberships/static/main.js
@@ -2,7 +2,30 @@
 const cancelButton = document.getElementById("cancel-button");
 const confirmButton = document.getElementById("confirm-button");
 
+const errorCancelButton = document.getElementById("error-cancel-button");
+const errorMessageDialog = document.getElementById("error-message");
+
+let activeModalStatus = false;
+let activeModal = '';
+
+function keydownHandler(event) {
+    if (event.key === "Escape" && activeModalStatus && activeModal === "confirmation") {
+        hideConfirmationDialog();
+    }
+}
+
+function oustideModalHandler(event) {
+    if (activeModalStatus && confirmationDialog === event.target) {
+        hideConfirmationDialog();
+        errorMessageDialog.close();
+    }
+}
+
 function showConfirmationDialog(form) {
+    activeModalStatus = true;
+    activeModal = "confirmation";
+    document.addEventListener("keydown", keydownHandler);
+    document.addEventListener("click", oustideModalHandler);
     const message = form.dataset.confirmationMessage;
     document.getElementById("confirmation-message").innerHTML = message;
     confirmationDialog.showModal();
@@ -21,6 +44,10 @@
 }
 
 function hideConfirmationDialog() {
+    activeModalStatus = false;
+    activeModal = '';
+    document.removeEventListener("keydown", keydownHandler);
+    document.removeEventListener("click", oustideModalHandler);
     confirmationDialog.close();
 }
 
@@ -44,12 +71,19 @@
             }
         });
     });
-});
 
-document.addEventListener("DOMContentLoaded", function () {
-    var errorCancelButton = document.getElementById("error-cancel-button");
-    var errorMessageDialog = document.getElementById("error-message");
     errorCancelButton.addEventListener("click", function () {
         errorMessageDialog.close();
     });
+
+    document.addEventListener("keydown", function (event) {
+        if (event.key === "Escape") {
+            errorMessageDialog.close();
+        }
+    });
+    document.addEventListener("click", function (event) {
+        if (errorMessageDialog === event.target) {
+            errorMessageDialog.close();
+        }
+    });
 });