diff --git a/.air.toml b/.air.toml
index d13f8c4f9..de97bd8b2 100644
--- a/.air.toml
+++ b/.air.toml
@@ -8,6 +8,15 @@ delay = 1000
 include_ext = ["go", "tmpl"]
 include_file = ["main.go"]
 include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
-exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
+exclude_dir = [
+  "models/fixtures",
+  "models/migrations/fixtures",
+  "modules/avatar/identicon/testdata",
+  "modules/avatar/testdata",
+  "modules/git/tests",
+  "modules/migration/file_format_testdata",
+  "routers/private/tests",
+  "services/gitdiff/testdata",
+]
 exclude_regex = ["_test.go$", "_gen.go$"]
 stop_on_error = true
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 8563aafd0..1b1b66c7d 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -4,7 +4,7 @@
   "features": {
     // installs nodejs into container
     "ghcr.io/devcontainers/features/node:1": {
-      "version":"20"
+      "version": "20"
     },
     "ghcr.io/devcontainers/features/git-lfs:1.1.0": {},
     "ghcr.io/devcontainers-contrib/features/poetry:2": {},
@@ -24,7 +24,7 @@
         "DavidAnson.vscode-markdownlint",
         "Vue.volar",
         "ms-azuretools.vscode-docker",
-        "zixuanchen.vitest-explorer",
+        "vitest.explorer",
         "qwtel.sqlite-viewer",
         "GitHub.vscode-pull-request-github"
       ]
diff --git a/.dockerignore b/.dockerignore
index d1a08977a..98ef52233 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -62,7 +62,6 @@ cpu.out
 /data
 /indexers
 /log
-/public/img/avatar
 /tests/integration/gitea-integration-*
 /tests/integration/indexers-*
 /tests/e2e/gitea-e2e-*
@@ -77,6 +76,7 @@ cpu.out
 /public/assets/js
 /public/assets/css
 /public/assets/fonts
+/public/assets/img/avatar
 /public/assets/img/webpack
 /vendor
 /web_src/fomantic/node_modules
diff --git a/.eslintrc.yaml b/.eslintrc.yaml
index b62b13cef..eeb3e20cb 100644
--- a/.eslintrc.yaml
+++ b/.eslintrc.yaml
@@ -42,10 +42,6 @@ overrides:
       worker: true
     rules:
       no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
-  - files: ["build/generate-images.js"]
-    rules:
-      i/no-unresolved: [0]
-      i/no-extraneous-dependencies: [0]
   - files: ["*.config.*"]
     rules:
       i/no-unused-modules: [0]
@@ -123,7 +119,7 @@ rules:
   "@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
   "@stylistic/js/block-spacing": [0]
   "@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
-  "@stylistic/js/comma-dangle": [2, only-multiline]
+  "@stylistic/js/comma-dangle": [2, always-multiline]
   "@stylistic/js/comma-spacing": [2, {before: false, after: true}]
   "@stylistic/js/comma-style": [2, last]
   "@stylistic/js/computed-property-spacing": [2, never]
@@ -290,7 +286,7 @@ rules:
   jquery/no-class: [0]
   jquery/no-clone: [2]
   jquery/no-closest: [0]
-  jquery/no-css: [0]
+  jquery/no-css: [2]
   jquery/no-data: [0]
   jquery/no-deferred: [2]
   jquery/no-delegate: [2]
@@ -413,7 +409,7 @@ rules:
   no-jquery/no-constructor-attributes: [2]
   no-jquery/no-contains: [2]
   no-jquery/no-context-prop: [2]
-  no-jquery/no-css: [0]
+  no-jquery/no-css: [2]
   no-jquery/no-data: [0]
   no-jquery/no-deferred: [2]
   no-jquery/no-delegate: [2]
diff --git a/.gitignore b/.gitignore
index 34c71b697..b883e079d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,7 +64,7 @@ cpu.out
 /data
 /indexers
 /log
-/public/img/avatar
+/public/assets/img/avatar
 /tests/integration/gitea-integration-*
 /tests/integration/indexers-*
 /tests/e2e/gitea-e2e-*
diff --git a/.gitpod.yml b/.gitpod.yml
index ed2f57f4b..f573d55a7 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -42,7 +42,7 @@ vscode:
     - DavidAnson.vscode-markdownlint
     - Vue.volar
     - ms-azuretools.vscode-docker
-    - zixuanchen.vitest-explorer
+    - vitest.explorer
     - qwtel.sqlite-viewer
     - GitHub.vscode-pull-request-github
 
diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml
index c7725159f..60cce7dbf 100644
--- a/.stylelintrc.yaml
+++ b/.stylelintrc.yaml
@@ -30,7 +30,7 @@ rules:
   "@stylistic/block-opening-brace-newline-after": null
   "@stylistic/block-opening-brace-newline-before": null
   "@stylistic/block-opening-brace-space-after": null
-  "@stylistic/block-opening-brace-space-before": null
+  "@stylistic/block-opening-brace-space-before": always
   "@stylistic/color-hex-case": lower
   "@stylistic/declaration-bang-space-after": never
   "@stylistic/declaration-bang-space-before": null
@@ -140,7 +140,7 @@ rules:
   function-disallowed-list: null
   function-linear-gradient-no-nonstandard-direction: true
   function-name-case: lower
-  function-no-unknown: null
+  function-no-unknown: true
   function-url-no-scheme-relative: null
   function-url-quotes: always
   function-url-scheme-allowed-list: null
@@ -168,7 +168,7 @@ rules:
   no-duplicate-selectors: true
   no-empty-source: true
   no-invalid-double-slash-comments: true
-  no-invalid-position-at-import-rule: null
+  no-invalid-position-at-import-rule: [true, ignoreAtRules: [tailwind]]
   no-irregular-whitespace: true
   no-unknown-animations: null
   no-unknown-custom-properties: null
@@ -181,6 +181,7 @@ rules:
   rule-empty-line-before: null
   rule-selector-property-disallowed-list: null
   scale-unlimited/declaration-strict-value: [[/color$/, font-weight], {ignoreValues: /^(inherit|transparent|unset|initial|currentcolor|none)$/, ignoreFunctions: false, disableFix: true, expandShorthand: true}]
+  selector-anb-no-unmatchable: true
   selector-attribute-name-disallowed-list: null
   selector-attribute-operator-allowed-list: null
   selector-attribute-operator-disallowed-list: null
diff --git a/Makefile b/Makefile
index 6735ffd1a..b1c4864c7 100644
--- a/Makefile
+++ b/Makefile
@@ -44,9 +44,6 @@ DOCKER_TAG ?= latest
 DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
 
 ifeq ($(HAS_GO), yes)
-	GOPATH ?= $(shell $(GO) env GOPATH)
-	export PATH := $(GOPATH)/bin:$(PATH)
-
 	CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
 	CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
 endif
@@ -148,6 +145,8 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN
 GO_DIRS := build cmd models modules routers services tests
 WEB_DIRS := web_src/js web_src/css
 
+ESLINT_FILES := web_src/js tools *.config.js tests/e2e
+STYLELINT_FILES := web_src/css web_src/js/components/*.vue
 SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github
 
 GO_SOURCES := $(wildcard *.go)
@@ -396,19 +395,19 @@ lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig
 
 .PHONY: lint-js
 lint-js: node_modules
-	npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js tests/e2e
+	npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES)
 
 .PHONY: lint-js-fix
 lint-js-fix: node_modules
-	npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js tests/e2e --fix
+	npx eslint --color --max-warnings=0 --ext js,vue $(ESLINT_FILES) --fix
 
 .PHONY: lint-css
 lint-css: node_modules
-	npx stylelint --color --max-warnings=0 web_src/css web_src/js/components/*.vue
+	npx stylelint --color --max-warnings=0 $(STYLELINT_FILES)
 
 .PHONY: lint-css-fix
 lint-css-fix: node_modules
-	npx stylelint --color --max-warnings=0 web_src/css web_src/js/components/*.vue --fix
+	npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix
 
 .PHONY: lint-swagger
 lint-swagger: node_modules
@@ -468,7 +467,7 @@ lint-yaml: .venv
 
 .PHONY: watch
 watch:
-	@bash build/watch.sh
+	@bash tools/watch.sh
 
 .PHONY: watch-frontend
 watch-frontend: node-check node_modules
@@ -962,7 +961,7 @@ $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json
 .PHONY: svg
 svg: node-check | node_modules
 	rm -rf $(SVG_DEST_DIR)
-	node build/generate-svg.js
+	node tools/generate-svg.js
 
 .PHONY: svg-check
 svg-check: svg
@@ -997,7 +996,7 @@ generate-gitignore:
 .PHONY: generate-images
 generate-images: | node_modules
 	npm install --no-save fabric@6.0.0-beta19 imagemin-zopfli@7
-	node build/generate-images.js $(TAGS)
+	node tools/generate-images.js $(TAGS)
 
 .PHONY: generate-manpage
 generate-manpage:
diff --git a/docs/content/administration/cmd-embedded.zh-cn.md b/docs/content/administration/cmd-embedded.zh-cn.md
index 4570bb58a..a2df1aa2f 100644
--- a/docs/content/administration/cmd-embedded.zh-cn.md
+++ b/docs/content/administration/cmd-embedded.zh-cn.md
@@ -37,7 +37,7 @@ gitea embedded list [--include-vendored] [patterns...]
 
 - 列出所有模板文件,无论在哪个虚拟目录下:`**.tmpl`
 - 列出所有邮件模板文件:`templates/mail/**.tmpl`
-- 列出 `public/img` 目录下的所有文件:`public/img/**`
+列出 `public/assets/img` 目录下的所有文件:`public/assets/img/**`
 
 不要忘记为模式使用引号,因为空格、`*` 和其他字符可能对命令行解释器有特殊含义。
 
@@ -49,8 +49,8 @@ gitea embedded list [--include-vendored] [patterns...]
 
 ```sh
 $ gitea embedded list '**openid**'
-public/img/auth/openid_connect.svg
-public/img/openid-16x16.png
+public/assets/img/auth/openid_connect.svg
+public/assets/img/openid-16x16.png
 templates/user/auth/finalize_openid.tmpl
 templates/user/auth/signin_openid.tmpl
 templates/user/auth/signup_openid_connect.tmpl
diff --git a/docs/content/contributing/guidelines-frontend.en-us.md b/docs/content/contributing/guidelines-frontend.en-us.md
index 263778071..b19101dd4 100644
--- a/docs/content/contributing/guidelines-frontend.en-us.md
+++ b/docs/content/contributing/guidelines-frontend.en-us.md
@@ -47,7 +47,7 @@ We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/h
 9. Avoid unnecessary `!important` in CSS, add comments to explain why it's necessary if it can't be avoided.
 10. Avoid mixing different events in one event listener, prefer to use individual event listeners for every event.
 11. Custom event names are recommended to use `ce-` prefix.
-12. Prefer using Tailwind CSS which is available via `tw-` prefix, e.g. `tw-relative`. Gitea's helper CSS classes use `gt-` prefix (`gt-df`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
+12. Prefer using Tailwind CSS which is available via `tw-` prefix, e.g. `tw-relative`. Gitea's helper CSS classes use `gt-` prefix (`gt-mono`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
 13. Avoid inline scripts & styles as much as possible, it's recommended to put JS code into JS files and use CSS classes. If inline scripts & styles are unavoidable, explain the reason why it can't be avoided.
 
 ### Accessibility / ARIA
diff --git a/docs/content/contributing/guidelines-frontend.zh-cn.md b/docs/content/contributing/guidelines-frontend.zh-cn.md
index ace0d97f4..961a331ac 100644
--- a/docs/content/contributing/guidelines-frontend.zh-cn.md
+++ b/docs/content/contributing/guidelines-frontend.zh-cn.md
@@ -47,7 +47,7 @@ HTML 页面由[Go HTML Template](https://pkg.go.dev/html/template)渲染。
 9. 避免在 CSS 中使用不必要的`!important`,如果无法避免,添加注释解释为什么需要它。
 10. 避免在一个事件监听器中混合不同的事件,优先为每个事件使用独立的事件监听器。
 11. 推荐使用自定义事件名称前缀`ce-`。
-12. 建议使用 Tailwind CSS,它可以通过 `tw-` 前缀获得,例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀(`gt-df`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。
+12. 建议使用 Tailwind CSS,它可以通过 `tw-` 前缀获得,例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀(`gt-mono`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。
 13. 尽量避免内联脚本和样式,建议将JS代码放入JS文件中并使用CSS类。如果内联脚本和样式不可避免,请解释无法避免的原因。
 
 ### 可访问性 / ARIA
diff --git a/docs/content/development/hacking-on-gitea.en-us.md b/docs/content/development/hacking-on-gitea.en-us.md
index 982dbcf6e..004e80382 100644
--- a/docs/content/development/hacking-on-gitea.en-us.md
+++ b/docs/content/development/hacking-on-gitea.en-us.md
@@ -214,7 +214,7 @@ REPO_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
 
 ### Building and adding SVGs
 
-SVG icons are built using the `make svg` target which compiles the icon sources defined in `build/generate-svg.js` into the output directory `public/assets/img/svg`. Custom icons can be added in the `web_src/svg` directory.
+SVG icons are built using the `make svg` target which compiles the icon sources into the output directory `public/assets/img/svg`. Custom icons can be added in the `web_src/svg` directory.
 
 ### Building the Logo
 
diff --git a/docs/content/development/hacking-on-gitea.zh-cn.md b/docs/content/development/hacking-on-gitea.zh-cn.md
index a31e1dc51..7dfea3053 100644
--- a/docs/content/development/hacking-on-gitea.zh-cn.md
+++ b/docs/content/development/hacking-on-gitea.zh-cn.md
@@ -201,7 +201,7 @@ REPO_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
 
 ### 构建和添加 SVGs
 
-SVG 图标是使用 `make svg` 目标构建的,该目标将 `build/generate-svg.js` 中定义的图标源编译到输出目录 `public/img/svg` 中。可以在 `web_src/svg` 目录中添加自定义图标。
+SVG 图标是使用 `make svg` 命令构建的,该命令将图标资源编译到输出目录 `public/assets/img/svg` 中。可以在 `web_src/svg` 目录中添加自定义图标。
 
 ### 构建 Logo
 
diff --git a/models/activities/notification.go b/models/activities/notification.go
index 4ca9f8027..211e84f41 100644
--- a/models/activities/notification.go
+++ b/models/activities/notification.go
@@ -20,6 +20,7 @@ import (
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
+	"code.gitea.io/gitea/modules/util"
 
 	"xorm.io/builder"
 )
@@ -841,3 +842,31 @@ func UpdateNotificationStatuses(ctx context.Context, user *user_model.User, curr
 		Update(n)
 	return err
 }
+
+// LoadIssuePullRequests loads all issues' pull requests if possible
+func (nl NotificationList) LoadIssuePullRequests(ctx context.Context) error {
+	issues := make(map[int64]*issues_model.Issue, len(nl))
+	for _, notification := range nl {
+		if notification.Issue != nil && notification.Issue.IsPull && notification.Issue.PullRequest == nil {
+			issues[notification.Issue.ID] = notification.Issue
+		}
+	}
+
+	if len(issues) == 0 {
+		return nil
+	}
+
+	pulls, err := issues_model.GetPullRequestByIssueIDs(ctx, util.KeysOfMap(issues))
+	if err != nil {
+		return err
+	}
+
+	for _, pull := range pulls {
+		if issue := issues[pull.IssueID]; issue != nil {
+			issue.PullRequest = pull
+			issue.PullRequest.Issue = issue
+		}
+	}
+
+	return nil
+}
diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go
index 2b15450c9..d3f9f3f3b 100644
--- a/models/asymkey/ssh_key_authorized_keys.go
+++ b/models/asymkey/ssh_key_authorized_keys.go
@@ -198,6 +198,8 @@ func RegeneratePublicKeys(ctx context.Context, t io.StringWriter) error {
 		if err != nil {
 			return err
 		}
+		defer f.Close()
+
 		scanner := bufio.NewScanner(f)
 		for scanner.Scan() {
 			line := scanner.Text()
@@ -207,11 +209,12 @@ func RegeneratePublicKeys(ctx context.Context, t io.StringWriter) error {
 			}
 			_, err = t.WriteString(line + "\n")
 			if err != nil {
-				f.Close()
 				return err
 			}
 		}
-		f.Close()
+		if err = scanner.Err(); err != nil {
+			return fmt.Errorf("RegeneratePublicKeys scan: %w", err)
+		}
 	}
 	return nil
 }
diff --git a/models/asymkey/ssh_key_authorized_principals.go b/models/asymkey/ssh_key_authorized_principals.go
index f3017c308..f85de12aa 100644
--- a/models/asymkey/ssh_key_authorized_principals.go
+++ b/models/asymkey/ssh_key_authorized_principals.go
@@ -120,6 +120,8 @@ func regeneratePrincipalKeys(ctx context.Context, t io.StringWriter) error {
 		if err != nil {
 			return err
 		}
+		defer f.Close()
+
 		scanner := bufio.NewScanner(f)
 		for scanner.Scan() {
 			line := scanner.Text()
@@ -129,11 +131,12 @@ func regeneratePrincipalKeys(ctx context.Context, t io.StringWriter) error {
 			}
 			_, err = t.WriteString(line + "\n")
 			if err != nil {
-				f.Close()
 				return err
 			}
 		}
-		f.Close()
+		if err = scanner.Err(); err != nil {
+			return fmt.Errorf("regeneratePrincipalKeys scan: %w", err)
+		}
 	}
 	return nil
 }
diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go
index bbe16483b..9c56e0f9a 100644
--- a/models/avatars/avatar.go
+++ b/models/avatars/avatar.go
@@ -24,7 +24,7 @@ import (
 
 const (
 	// DefaultAvatarClass is the default class of a rendered avatar
-	DefaultAvatarClass = "ui avatar gt-vm"
+	DefaultAvatarClass = "ui avatar tw-align-middle"
 	// DefaultAvatarPixelSize is the default size in pixels of a rendered avatar
 	DefaultAvatarPixelSize = 28
 )
diff --git a/models/issues/issue.go b/models/issues/issue.go
index 54ef5cec7..11256f788 100644
--- a/models/issues/issue.go
+++ b/models/issues/issue.go
@@ -194,20 +194,6 @@ func (issue *Issue) IsTimetrackerEnabled(ctx context.Context) bool {
 	return issue.Repo.IsTimetrackerEnabled(ctx)
 }
 
-// GetPullRequest returns the issue pull request
-func (issue *Issue) GetPullRequest(ctx context.Context) (pr *PullRequest, err error) {
-	if !issue.IsPull {
-		return nil, fmt.Errorf("Issue is not a pull request")
-	}
-
-	pr, err = GetPullRequestByIssueID(ctx, issue.ID)
-	if err != nil {
-		return nil, err
-	}
-	pr.Issue = issue
-	return pr, err
-}
-
 // LoadPoster loads poster
 func (issue *Issue) LoadPoster(ctx context.Context) (err error) {
 	if issue.Poster == nil && issue.PosterID != 0 {
diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go
index 0fb8447ff..9ccb93bf4 100644
--- a/models/issues/issue_list.go
+++ b/models/issues/issue_list.go
@@ -370,6 +370,9 @@ func (issues IssueList) LoadPullRequests(ctx context.Context) error {
 
 	for _, issue := range issues {
 		issue.PullRequest = pullRequestMaps[issue.ID]
+		if issue.PullRequest != nil {
+			issue.PullRequest.Issue = issue
+		}
 	}
 	return nil
 }
diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go
index d539ed540..084f7d624 100644
--- a/models/issues/pull_list.go
+++ b/models/issues/pull_list.go
@@ -11,7 +11,6 @@ import (
 	access_model "code.gitea.io/gitea/models/perm/access"
 	"code.gitea.io/gitea/models/unit"
 	user_model "code.gitea.io/gitea/models/user"
-	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/util"
 
@@ -23,7 +22,7 @@ type PullRequestsOptions struct {
 	db.ListOptions
 	State       string
 	SortType    string
-	Labels      []string
+	Labels      []int64
 	MilestoneID int64
 }
 
@@ -36,11 +35,9 @@ func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullR
 		sess.And("issue.is_closed=?", opts.State == "closed")
 	}
 
-	if labelIDs, err := base.StringsToInt64s(opts.Labels); err != nil {
-		return nil, err
-	} else if len(labelIDs) > 0 {
+	if len(opts.Labels) > 0 {
 		sess.Join("INNER", "issue_label", "issue.id = issue_label.issue_id").
-			In("issue_label.label_id", labelIDs)
+			In("issue_label.label_id", opts.Labels)
 	}
 
 	if opts.MilestoneID > 0 {
@@ -220,3 +217,12 @@ func HasMergedPullRequestInRepo(ctx context.Context, repoID, posterID int64) (bo
 		Limit(1).
 		Get(new(Issue))
 }
+
+// GetPullRequestByIssueIDs returns all pull requests by issue ids
+func GetPullRequestByIssueIDs(ctx context.Context, issueIDs []int64) (PullRequestList, error) {
+	prs := make([]*PullRequest, 0, len(issueIDs))
+	return prs, db.GetEngine(ctx).
+		Where("issue_id > 0").
+		In("issue_id", issueIDs).
+		Find(&prs)
+}
diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go
index 213838abe..1a43d8994 100644
--- a/models/issues/pull_test.go
+++ b/models/issues/pull_test.go
@@ -67,7 +67,6 @@ func TestPullRequestsNewest(t *testing.T) {
 		},
 		State:    "open",
 		SortType: "newest",
-		Labels:   []string{},
 	})
 	assert.NoError(t, err)
 	assert.EqualValues(t, 3, count)
@@ -114,7 +113,6 @@ func TestPullRequestsOldest(t *testing.T) {
 		},
 		State:    "open",
 		SortType: "oldest",
-		Labels:   []string{},
 	})
 	assert.NoError(t, err)
 	assert.EqualValues(t, 3, count)
diff --git a/models/issues/review.go b/models/issues/review.go
index fc110630e..70aba0f94 100644
--- a/models/issues/review.go
+++ b/models/issues/review.go
@@ -239,11 +239,11 @@ type CreateReviewOptions struct {
 
 // IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals)
 func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewer *user_model.User) (bool, error) {
-	pr, err := GetPullRequestByIssueID(ctx, issue.ID)
-	if err != nil {
+	if err := issue.LoadPullRequest(ctx); err != nil {
 		return false, err
 	}
 
+	pr := issue.PullRequest
 	rule, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
 	if err != nil {
 		return false, err
@@ -271,11 +271,10 @@ func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewer *user_model.
 
 // IsOfficialReviewerTeam check if reviewer in this team can make official reviews in issue (counts towards required approvals)
 func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organization.Team) (bool, error) {
-	pr, err := GetPullRequestByIssueID(ctx, issue.ID)
-	if err != nil {
+	if err := issue.LoadPullRequest(ctx); err != nil {
 		return false, err
 	}
-	pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
+	pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, issue.PullRequest.BaseRepoID, issue.PullRequest.BaseBranch)
 	if err != nil {
 		return false, err
 	}
diff --git a/models/organization/org.go b/models/organization/org.go
index b4919defb..47230bdc3 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -319,8 +319,9 @@ func CreateOrganization(ctx context.Context, org *Organization, owner *user_mode
 
 	// Add initial creator to organization and owner team.
 	if err = db.Insert(ctx, &OrgUser{
-		UID:   owner.ID,
-		OrgID: org.ID,
+		UID:      owner.ID,
+		OrgID:    org.ID,
+		IsPublic: setting.Service.DefaultOrgMemberVisible,
 	}); err != nil {
 		return fmt.Errorf("insert org-user relation: %w", err)
 	}
diff --git a/models/user/email_address.go b/models/user/email_address.go
index f2ee5e61b..45bcc54aa 100644
--- a/models/user/email_address.go
+++ b/models/user/email_address.go
@@ -443,7 +443,7 @@ func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmail
 		cond = cond.And(builder.Eq{"email_address.is_activated": opts.IsActivated.Value()})
 	}
 
-	count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.ID = email_address.uid").
+	count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.id = email_address.uid").
 		Where(cond).Count(new(EmailAddress))
 	if err != nil {
 		return nil, 0, fmt.Errorf("Count: %w", err)
@@ -459,7 +459,7 @@ func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmail
 	emails := make([]*SearchEmailResult, 0, opts.PageSize)
 	err = db.GetEngine(ctx).Table("email_address").
 		Select("email_address.*, `user`.name, `user`.full_name").
-		Join("INNER", "`user`", "`user`.ID = email_address.uid").
+		Join("INNER", "`user`", "`user`.id = email_address.uid").
 		Where(cond).
 		OrderBy(orderby).
 		Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
diff --git a/modules/actions/log.go b/modules/actions/log.go
index cdf18646a..c38082b5d 100644
--- a/modules/actions/log.go
+++ b/modules/actions/log.go
@@ -100,7 +100,7 @@ func ReadLogs(ctx context.Context, inStorage bool, filename string, offset, limi
 	}
 
 	if err := scanner.Err(); err != nil {
-		return nil, fmt.Errorf("scan: %w", err)
+		return nil, fmt.Errorf("ReadLogs scan: %w", err)
 	}
 
 	return rows, nil
diff --git a/modules/actions/task_state.go b/modules/actions/task_state.go
index fe925bbb5..31a74be3f 100644
--- a/modules/actions/task_state.go
+++ b/modules/actions/task_state.go
@@ -41,6 +41,12 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
 	}
 	logIndex += preStep.LogLength
 
+	// lastHasRunStep is the last step that has run.
+	// For example,
+	// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
+	// 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
+	// 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
+	// So its Stopped is the Started of postStep when there are no more steps to run.
 	var lastHasRunStep *actions_model.ActionTaskStep
 	for _, step := range task.Steps {
 		if step.Status.HasRun() {
@@ -56,11 +62,15 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
 		Name:   postStepName,
 		Status: actions_model.StatusWaiting,
 	}
-	if task.Status.IsDone() {
+	// If the lastHasRunStep is the last step, or it has failed, postStep has started.
+	if lastHasRunStep.Status.IsFailure() || lastHasRunStep == task.Steps[len(task.Steps)-1] {
 		postStep.LogIndex = logIndex
 		postStep.LogLength = task.LogLength - postStep.LogIndex
-		postStep.Status = task.Status
 		postStep.Started = lastHasRunStep.Stopped
+		postStep.Status = actions_model.StatusRunning
+	}
+	if task.Status.IsDone() {
+		postStep.Status = task.Status
 		postStep.Stopped = task.Stopped
 	}
 	ret := make([]*actions_model.ActionTaskStep, 0, len(task.Steps)+2)
diff --git a/modules/actions/task_state_test.go b/modules/actions/task_state_test.go
index 3a599fbcb..28213d781 100644
--- a/modules/actions/task_state_test.go
+++ b/modules/actions/task_state_test.go
@@ -103,6 +103,40 @@ func TestFullSteps(t *testing.T) {
 				{Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 100, LogLength: 0, Started: 10100, Stopped: 10100},
 			},
 		},
+		{
+			name: "all steps finished but task is running",
+			task: &actions_model.ActionTask{
+				Steps: []*actions_model.ActionTaskStep{
+					{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
+				},
+				Status:    actions_model.StatusRunning,
+				Started:   10000,
+				Stopped:   0,
+				LogLength: 100,
+			},
+			want: []*actions_model.ActionTaskStep{
+				{Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
+				{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
+				{Name: postStepName, Status: actions_model.StatusRunning, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 0},
+			},
+		},
+		{
+			name: "skipped task",
+			task: &actions_model.ActionTask{
+				Steps: []*actions_model.ActionTaskStep{
+					{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+				},
+				Status:    actions_model.StatusSkipped,
+				Started:   0,
+				Stopped:   0,
+				LogLength: 0,
+			},
+			want: []*actions_model.ActionTaskStep{
+				{Name: preStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+				{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+				{Name: postStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+			},
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/modules/base/tool.go b/modules/base/tool.go
index 231507546..e4c3fb181 100644
--- a/modules/base/tool.go
+++ b/modules/base/tool.go
@@ -150,13 +150,16 @@ func TruncateString(str string, limit int) string {
 
 // StringsToInt64s converts a slice of string to a slice of int64.
 func StringsToInt64s(strs []string) ([]int64, error) {
-	ints := make([]int64, len(strs))
-	for i := range strs {
-		n, err := strconv.ParseInt(strs[i], 10, 64)
+	if strs == nil {
+		return nil, nil
+	}
+	ints := make([]int64, 0, len(strs))
+	for _, s := range strs {
+		n, err := strconv.ParseInt(s, 10, 64)
 		if err != nil {
-			return ints, err
+			return nil, err
 		}
-		ints[i] = n
+		ints = append(ints, n)
 	}
 	return ints, nil
 }
diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go
index d28deb593..f21b89c74 100644
--- a/modules/base/tool_test.go
+++ b/modules/base/tool_test.go
@@ -138,12 +138,13 @@ func TestStringsToInt64s(t *testing.T) {
 		assert.NoError(t, err)
 		assert.Equal(t, expected, result)
 	}
+	testSuccess(nil, nil)
 	testSuccess([]string{}, []int64{})
 	testSuccess([]string{"-1234"}, []int64{-1234})
-	testSuccess([]string{"1", "4", "16", "64", "256"},
-		[]int64{1, 4, 16, 64, 256})
+	testSuccess([]string{"1", "4", "16", "64", "256"}, []int64{1, 4, 16, 64, 256})
 
-	_, err := StringsToInt64s([]string{"-1", "a", "$"})
+	ints, err := StringsToInt64s([]string{"-1", "a"})
+	assert.Len(t, ints, 0)
 	assert.Error(t, err)
 }
 
diff --git a/modules/git/commit.go b/modules/git/commit.go
index c30f1e35e..00681e3b2 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -9,6 +9,7 @@ import (
 	"bytes"
 	"context"
 	"errors"
+	"fmt"
 	"io"
 	"os/exec"
 	"strconv"
@@ -390,6 +391,9 @@ func (c *Commit) GetSubModules() (*ObjectCache, error) {
 			}
 		}
 	}
+	if err = scanner.Err(); err != nil {
+		return nil, fmt.Errorf("GetSubModules scan: %w", err)
+	}
 
 	return c.submoduleCache, nil
 }
diff --git a/modules/git/repo.go b/modules/git/repo.go
index 60078f327..e8a7016d9 100644
--- a/modules/git/repo.go
+++ b/modules/git/repo.go
@@ -283,7 +283,7 @@ type DivergeObject struct {
 // GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
 func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (do DivergeObject, err error) {
 	cmd := NewCommand(ctx, "rev-list", "--count", "--left-right").
-		AddDynamicArguments(baseBranch + "..." + targetBranch)
+		AddDynamicArguments(baseBranch + "..." + targetBranch).AddArguments("--")
 	stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
 	if err != nil {
 		return do, err
diff --git a/modules/git/repo_stats.go b/modules/git/repo_stats.go
index 41f94e24f..83220104b 100644
--- a/modules/git/repo_stats.go
+++ b/modules/git/repo_stats.go
@@ -124,6 +124,10 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
 					}
 				}
 			}
+			if err = scanner.Err(); err != nil {
+				_ = stdoutReader.Close()
+				return fmt.Errorf("GetCodeActivityStats scan: %w", err)
+			}
 			a := make([]*CodeActivityAuthor, 0, len(authors))
 			for _, v := range authors {
 				a = append(a, v)
diff --git a/modules/graceful/manager_unix.go b/modules/graceful/manager_unix.go
index f49c42650..d03fff9b5 100644
--- a/modules/graceful/manager_unix.go
+++ b/modules/graceful/manager_unix.go
@@ -59,8 +59,8 @@ func (g *Manager) start() {
 	go func() {
 		defer func() {
 			close(startupDone)
-			// Close the unused listeners and ignore the error here there's not much we can do with it, they're logged in the CloseProvidedListeners function
-			_ = CloseProvidedListeners()
+			// Close the unused listeners
+			closeProvidedListeners()
 		}()
 		// Wait for all servers to be created
 		g.createServerCond.L.Lock()
diff --git a/modules/graceful/net_unix.go b/modules/graceful/net_unix.go
index 4f8c036a6..796e00507 100644
--- a/modules/graceful/net_unix.go
+++ b/modules/graceful/net_unix.go
@@ -129,25 +129,17 @@ func getProvidedFDs() (savedErr error) {
 	return savedErr
 }
 
-// CloseProvidedListeners closes all unused provided listeners.
-func CloseProvidedListeners() error {
+// closeProvidedListeners closes all unused provided listeners.
+func closeProvidedListeners() {
 	mutex.Lock()
 	defer mutex.Unlock()
-	var returnableError error
 	for _, l := range providedListeners {
 		err := l.Close()
 		if err != nil {
 			log.Error("Error in closing unused provided listener: %v", err)
-			if returnableError != nil {
-				returnableError = fmt.Errorf("%v & %w", returnableError, err)
-			} else {
-				returnableError = err
-			}
 		}
 	}
 	providedListeners = []net.Listener{}
-
-	return returnableError
 }
 
 // DefaultGetListener obtains a listener for the stream-oriented local network address:
diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go
index d7f735e95..c607d780e 100644
--- a/modules/indexer/code/bleve/bleve.go
+++ b/modules/indexer/code/bleve/bleve.go
@@ -39,6 +39,8 @@ import (
 const (
 	unicodeNormalizeName = "unicodeNormalize"
 	maxBatchSize         = 16
+	// fuzzyDenominator determines the levenshtein distance per each character of a keyword
+	fuzzyDenominator = 4
 )
 
 func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error {
@@ -239,15 +241,12 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
 		keywordQuery query.Query
 	)
 
+	phraseQuery := bleve.NewMatchPhraseQuery(opts.Keyword)
+	phraseQuery.FieldVal = "Content"
+	phraseQuery.Analyzer = repoIndexerAnalyzer
+	keywordQuery = phraseQuery
 	if opts.IsKeywordFuzzy {
-		phraseQuery := bleve.NewMatchPhraseQuery(opts.Keyword)
-		phraseQuery.FieldVal = "Content"
-		phraseQuery.Analyzer = repoIndexerAnalyzer
-		keywordQuery = phraseQuery
-	} else {
-		prefixQuery := bleve.NewPrefixQuery(opts.Keyword)
-		prefixQuery.FieldVal = "Content"
-		keywordQuery = prefixQuery
+		phraseQuery.Fuzziness = len(opts.Keyword) / fuzzyDenominator
 	}
 
 	if len(opts.RepoIDs) > 0 {
diff --git a/modules/indexer/internal/bleve/query.go b/modules/indexer/internal/bleve/query.go
index b96875343..21422b281 100644
--- a/modules/indexer/internal/bleve/query.go
+++ b/modules/indexer/internal/bleve/query.go
@@ -20,17 +20,11 @@ func NumericEqualityQuery(value int64, field string) *query.NumericRangeQuery {
 }
 
 // MatchPhraseQuery generates a match phrase query for the given phrase, field and analyzer
-func MatchPhraseQuery(matchPhrase, field, analyzer string) *query.MatchPhraseQuery {
+func MatchPhraseQuery(matchPhrase, field, analyzer string, fuzziness int) *query.MatchPhraseQuery {
 	q := bleve.NewMatchPhraseQuery(matchPhrase)
 	q.FieldVal = field
 	q.Analyzer = analyzer
-	return q
-}
-
-// PrefixQuery generates a match prefix query for the given prefix and field
-func PrefixQuery(matchPrefix, field string) *query.PrefixQuery {
-	q := bleve.NewPrefixQuery(matchPrefix)
-	q.FieldVal = field
+	q.Fuzziness = fuzziness
 	return q
 }
 
diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go
index 927ad58cd..1f54be721 100644
--- a/modules/indexer/issues/bleve/bleve.go
+++ b/modules/indexer/issues/bleve/bleve.go
@@ -35,7 +35,11 @@ func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error {
 	})
 }
 
-const maxBatchSize = 16
+const (
+	maxBatchSize = 16
+	// fuzzyDenominator determines the levenshtein distance per each character of a keyword
+	fuzzyDenominator = 4
+)
 
 // IndexerData an update to the issue indexer
 type IndexerData internal.IndexerData
@@ -156,19 +160,16 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
 	var queries []query.Query
 
 	if options.Keyword != "" {
+		fuzziness := 0
 		if options.IsFuzzyKeyword {
-			queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{
-				inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer),
-				inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer),
-				inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer),
-			}...))
-		} else {
-			queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{
-				inner_bleve.PrefixQuery(options.Keyword, "title"),
-				inner_bleve.PrefixQuery(options.Keyword, "content"),
-				inner_bleve.PrefixQuery(options.Keyword, "comments"),
-			}...))
+			fuzziness = len(options.Keyword) / fuzzyDenominator
 		}
+
+		queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{
+			inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer, fuzziness),
+			inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer, fuzziness),
+			inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer, fuzziness),
+		}...))
 	}
 
 	if len(options.RepoIDs) > 0 || options.AllPublic {
diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go
index 91aafd589..2209377c2 100644
--- a/modules/indexer/issues/internal/tests/tests.go
+++ b/modules/indexer/issues/internal/tests/tests.go
@@ -515,10 +515,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByCreatedDesc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByCreatedDesc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByCreatedDesc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
@@ -533,10 +531,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByUpdatedDesc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByUpdatedDesc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByUpdatedDesc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
@@ -551,10 +547,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByCommentsDesc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByCommentsDesc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByCommentsDesc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
@@ -569,10 +563,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByDeadlineDesc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByDeadlineDesc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByDeadlineDesc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
@@ -587,10 +579,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByCreatedAsc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByCreatedAsc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByCreatedAsc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
@@ -605,10 +595,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByUpdatedAsc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByUpdatedAsc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByUpdatedAsc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
@@ -623,10 +611,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByCommentsAsc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByCommentsAsc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByCommentsAsc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
@@ -641,10 +627,8 @@ var cases = []*testIndexerCase{
 	{
 		Name: "SortByDeadlineAsc",
 		SearchOptions: &internal.SearchOptions{
-			Paginator: &db.ListOptions{
-				ListAll: true,
-			},
-			SortBy: internal.SortByDeadlineAsc,
+			Paginator: &db.ListOptionsAll,
+			SortBy:    internal.SortByDeadlineAsc,
 		},
 		Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
 			assert.Equal(t, len(data), len(result.Hits))
diff --git a/modules/indexer/issues/util.go b/modules/indexer/issues/util.go
index 510b4060b..9861c808d 100644
--- a/modules/indexer/issues/util.go
+++ b/modules/indexer/issues/util.go
@@ -61,9 +61,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD
 	)
 	{
 		reviews, err := issue_model.FindReviews(ctx, issue_model.FindReviewOptions{
-			ListOptions: db.ListOptions{
-				ListAll: true,
-			},
+			ListOptions:  db.ListOptionsAll,
 			IssueID:      issueID,
 			OfficialOnly: false,
 		})
diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go
index 570c4f470..1dd26eb8a 100644
--- a/modules/markup/csv/csv.go
+++ b/modules/markup/csv/csv.go
@@ -6,6 +6,7 @@ package markup
 import (
 	"bufio"
 	"bytes"
+	"fmt"
 	"html"
 	"io"
 	"regexp"
@@ -123,6 +124,9 @@ func (Renderer) fallbackRender(input io.Reader, tmpBlock *bufio.Writer) error {
 			return err
 		}
 	}
+	if err = scan.Err(); err != nil {
+		return fmt.Errorf("fallbackRender scan: %w", err)
+	}
 
 	_, err = tmpBlock.WriteString("</pre>")
 	if err != nil {
diff --git a/modules/util/slice.go b/modules/util/slice.go
index f00e84bf0..9c878c24b 100644
--- a/modules/util/slice.go
+++ b/modules/util/slice.go
@@ -54,7 +54,7 @@ func Sorted[S ~[]E, E cmp.Ordered](values S) S {
 	return values
 }
 
-// TODO: Replace with "maps.Values" once available
+// TODO: Replace with "maps.Values" once available, current it only in golang.org/x/exp/maps but not in standard library
 func ValuesOfMap[K comparable, V any](m map[K]V) []V {
 	values := make([]V, 0, len(m))
 	for _, v := range m {
@@ -62,3 +62,12 @@ func ValuesOfMap[K comparable, V any](m map[K]V) []V {
 	}
 	return values
 }
+
+// TODO: Replace with "maps.Keys" once available, current it only in golang.org/x/exp/maps but not in standard library
+func KeysOfMap[K comparable, V any](m map[K]V) []K {
+	keys := make([]K, 0, len(m))
+	for k := range m {
+		keys = append(keys, k)
+	}
+	return keys
+}
diff --git a/options/license/threeparttable b/options/license/threeparttable
new file mode 100644
index 000000000..498b72822
--- /dev/null
+++ b/options/license/threeparttable
@@ -0,0 +1,3 @@
+This file may be distributed, modified, and used in other works with just
+one restriction: modified versions must clearly indicate the modification
+(a name change, or a displayed message, or ?).
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 620c469bd..e93be5221 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -115,6 +115,7 @@ loading = Loading…
 error = Error
 error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it.
 go_back = Go Back
+invalid_data = Invalid data: %v
 
 never = Never
 unknown = Unknown
@@ -1333,6 +1334,8 @@ editor.file_editing_no_longer_exists = The file being edited, "%s", no longer ex
 editor.file_deleting_no_longer_exists = The file being deleted, "%s", no longer exists in this repository.
 editor.file_changed_while_editing = The file contents have changed since you started editing. <a target="_blank" rel="noopener noreferrer" href="%s">Click here</a> to see them or <strong>Commit Changes again</strong> to overwrite them.
 editor.file_already_exists = A file named "%s" already exists in this repository.
+editor.commit_id_not_matching = The Commit ID does not match the ID when you began editing.  Commit into a patch branch and then merge.
+editor.push_out_of_date = The push appears to be out of date.
 editor.commit_empty_file_header = Commit an empty file
 editor.commit_empty_file_text = The file you're about to commit is empty. Proceed?
 editor.no_changes_to_show = There are no changes to show.
@@ -3133,7 +3136,7 @@ auths.tip.nextcloud = Register a new OAuth consumer on your instance using the f
 auths.tip.dropbox = Create a new application at https://www.dropbox.com/developers/apps
 auths.tip.facebook = Register a new application at https://developers.facebook.com/apps and add the product "Facebook Login"
 auths.tip.github = Register a new OAuth application on https://github.com/settings/applications/new
-auths.tip.gitlab = Register a new application on https://gitlab.com/profile/applications
+auths.tip.gitlab_new = Register a new application on https://gitlab.com/-/profile/applications
 auths.tip.google_plus = Obtain OAuth2 client credentials from the Google API console at https://console.developers.google.com/
 auths.tip.openid_connect = Use the OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) to specify the endpoints
 auths.tip.twitter = Go to https://dev.twitter.com/apps, create an application and ensure that the “Allow this application to be used to Sign in with Twitter” option is enabled
@@ -3671,6 +3674,7 @@ runs.pushed_by = pushed by
 runs.workflow = Workflow
 runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s
 runs.no_matching_online_runner_helper = No matching online runner with label: %s
+runs.no_job_without_needs = The workflow must contain at least one job without dependencies.
 runs.actor = Actor
 runs.status = Status
 runs.actors_no_select = All actors
diff --git a/package-lock.json b/package-lock.json
index b87b1d592..f6df16f2a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -85,7 +85,7 @@
         "eslint-plugin-vue": "9.23.0",
         "eslint-plugin-vue-scoped-css": "2.7.2",
         "eslint-plugin-wc": "2.0.4",
-        "jsdom": "24.0.0",
+        "happy-dom": "14.2.0",
         "markdownlint-cli": "0.39.0",
         "postcss-html": "1.6.0",
         "stylelint": "16.2.1",
@@ -130,81 +130,17 @@
       }
     },
     "node_modules/@babel/code-frame": {
-      "version": "7.23.5",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
-      "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
+      "version": "7.24.2",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
+      "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
       "dependencies": {
-        "@babel/highlight": "^7.23.4",
-        "chalk": "^2.4.2"
+        "@babel/highlight": "^7.24.2",
+        "picocolors": "^1.0.0"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
-    "node_modules/@babel/code-frame/node_modules/ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dependencies": {
-        "color-convert": "^1.9.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/@babel/code-frame/node_modules/chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dependencies": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/@babel/code-frame/node_modules/color-convert": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dependencies": {
-        "color-name": "1.1.3"
-      }
-    },
-    "node_modules/@babel/code-frame/node_modules/color-name": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
-    },
-    "node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
-    "node_modules/@babel/code-frame/node_modules/has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/@babel/code-frame/node_modules/supports-color": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dependencies": {
-        "has-flag": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/@babel/helper-validator-identifier": {
       "version": "7.22.20",
       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
@@ -214,13 +150,14 @@
       }
     },
     "node_modules/@babel/highlight": {
-      "version": "7.23.4",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
-      "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
+      "version": "7.24.2",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
+      "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
       "dependencies": {
         "@babel/helper-validator-identifier": "^7.22.20",
         "chalk": "^2.4.2",
-        "js-tokens": "^4.0.0"
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.0.0"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -296,9 +233,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.24.0",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz",
-      "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==",
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz",
+      "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==",
       "bin": {
         "parser": "bin/babel-parser.js"
       },
@@ -307,9 +244,9 @@
       }
     },
     "node_modules/@babel/runtime": {
-      "version": "7.24.0",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz",
-      "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==",
+      "version": "7.24.1",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz",
+      "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==",
       "dependencies": {
         "regenerator-runtime": "^0.14.0"
       },
@@ -2204,9 +2141,9 @@
       }
     },
     "node_modules/@types/eslint": {
-      "version": "8.56.5",
-      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz",
-      "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==",
+      "version": "8.56.6",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.6.tgz",
+      "integrity": "sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==",
       "dependencies": {
         "@types/estree": "*",
         "@types/json-schema": "*"
@@ -2256,9 +2193,9 @@
       "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
     },
     "node_modules/@types/node": {
-      "version": "20.11.27",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz",
-      "integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==",
+      "version": "20.11.30",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz",
+      "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==",
       "dependencies": {
         "undici-types": "~5.26.4"
       }
@@ -2301,16 +2238,16 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz",
-      "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz",
+      "integrity": "sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==",
       "dev": true,
       "dependencies": {
         "@eslint-community/regexpp": "^4.5.1",
-        "@typescript-eslint/scope-manager": "7.2.0",
-        "@typescript-eslint/type-utils": "7.2.0",
-        "@typescript-eslint/utils": "7.2.0",
-        "@typescript-eslint/visitor-keys": "7.2.0",
+        "@typescript-eslint/scope-manager": "7.3.1",
+        "@typescript-eslint/type-utils": "7.3.1",
+        "@typescript-eslint/utils": "7.3.1",
+        "@typescript-eslint/visitor-keys": "7.3.1",
         "debug": "^4.3.4",
         "graphemer": "^1.4.0",
         "ignore": "^5.2.4",
@@ -2319,7 +2256,7 @@
         "ts-api-utils": "^1.0.1"
       },
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2336,19 +2273,19 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz",
-      "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.1.tgz",
+      "integrity": "sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "7.2.0",
-        "@typescript-eslint/types": "7.2.0",
-        "@typescript-eslint/typescript-estree": "7.2.0",
-        "@typescript-eslint/visitor-keys": "7.2.0",
+        "@typescript-eslint/scope-manager": "7.3.1",
+        "@typescript-eslint/types": "7.3.1",
+        "@typescript-eslint/typescript-estree": "7.3.1",
+        "@typescript-eslint/visitor-keys": "7.3.1",
         "debug": "^4.3.4"
       },
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2364,16 +2301,16 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz",
-      "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz",
+      "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.2.0",
-        "@typescript-eslint/visitor-keys": "7.2.0"
+        "@typescript-eslint/types": "7.3.1",
+        "@typescript-eslint/visitor-keys": "7.3.1"
       },
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2381,18 +2318,18 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz",
-      "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz",
+      "integrity": "sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "7.2.0",
-        "@typescript-eslint/utils": "7.2.0",
+        "@typescript-eslint/typescript-estree": "7.3.1",
+        "@typescript-eslint/utils": "7.3.1",
         "debug": "^4.3.4",
         "ts-api-utils": "^1.0.1"
       },
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2408,12 +2345,12 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz",
-      "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz",
+      "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==",
       "dev": true,
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2421,13 +2358,13 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz",
-      "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz",
+      "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.2.0",
-        "@typescript-eslint/visitor-keys": "7.2.0",
+        "@typescript-eslint/types": "7.3.1",
+        "@typescript-eslint/visitor-keys": "7.3.1",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
@@ -2436,7 +2373,7 @@
         "ts-api-utils": "^1.0.1"
       },
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2449,21 +2386,21 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz",
-      "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz",
+      "integrity": "sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
         "@types/json-schema": "^7.0.12",
         "@types/semver": "^7.5.0",
-        "@typescript-eslint/scope-manager": "7.2.0",
-        "@typescript-eslint/types": "7.2.0",
-        "@typescript-eslint/typescript-estree": "7.2.0",
+        "@typescript-eslint/scope-manager": "7.3.1",
+        "@typescript-eslint/types": "7.3.1",
+        "@typescript-eslint/typescript-estree": "7.3.1",
         "semver": "^7.5.4"
       },
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2474,16 +2411,16 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz",
-      "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz",
+      "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.2.0",
+        "@typescript-eslint/types": "7.3.1",
         "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
-        "node": "^16.0.0 || >=18.0.0"
+        "node": "^18.18.0 || >=20.0.0"
       },
       "funding": {
         "type": "opencollective",
@@ -2978,18 +2915,6 @@
         "webpack": ">=5"
       }
     },
-    "node_modules/agent-base": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
-      "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
-      "dev": true,
-      "dependencies": {
-        "debug": "^4.3.4"
-      },
-      "engines": {
-        "node": ">= 14"
-      }
-    },
     "node_modules/ajv": {
       "version": "8.12.0",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
@@ -3146,15 +3071,16 @@
       }
     },
     "node_modules/array-includes": {
-      "version": "3.1.7",
-      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz",
-      "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==",
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+      "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1",
-        "get-intrinsic": "^1.2.1",
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
         "is-string": "^1.0.7"
       },
       "engines": {
@@ -3173,35 +3099,17 @@
         "node": ">=8"
       }
     },
-    "node_modules/array.prototype.filter": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz",
-      "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==",
-      "dev": true,
-      "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1",
-        "es-array-method-boxes-properly": "^1.0.0",
-        "is-string": "^1.0.7"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/array.prototype.findlastindex": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz",
-      "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==",
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
+      "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.5",
+        "call-bind": "^1.0.7",
         "define-properties": "^1.2.1",
-        "es-abstract": "^1.22.3",
+        "es-abstract": "^1.23.2",
         "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
         "es-shim-unscopables": "^1.0.2"
       },
       "engines": {
@@ -3332,21 +3240,6 @@
         "astring": "bin/astring"
       }
     },
-    "node_modules/asynciterator.prototype": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz",
-      "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==",
-      "dev": true,
-      "dependencies": {
-        "has-symbols": "^1.0.3"
-      }
-    },
-    "node_modules/asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-      "dev": true
-    },
     "node_modules/atob": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -3582,9 +3475,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001597",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz",
-      "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==",
+      "version": "1.0.30001599",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz",
+      "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==",
       "funding": [
         {
           "type": "opencollective",
@@ -3868,18 +3761,6 @@
       "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
       "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="
     },
-    "node_modules/combined-stream": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
-      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-      "dev": true,
-      "dependencies": {
-        "delayed-stream": "~1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/commander": {
       "version": "8.3.0",
       "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
@@ -3909,12 +3790,12 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
     },
     "node_modules/core-js-compat": {
-      "version": "3.36.0",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz",
-      "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==",
+      "version": "3.36.1",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz",
+      "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==",
       "dev": true,
       "dependencies": {
-        "browserslist": "^4.22.3"
+        "browserslist": "^4.23.0"
       },
       "funding": {
         "type": "opencollective",
@@ -4106,18 +3987,6 @@
       "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
       "dev": true
     },
-    "node_modules/cssstyle": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
-      "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==",
-      "dev": true,
-      "dependencies": {
-        "rrweb-cssom": "^0.6.0"
-      },
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/csstype": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -4580,17 +4449,55 @@
       "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==",
       "dev": true
     },
-    "node_modules/data-urls": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
-      "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
+    "node_modules/data-view-buffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
+      "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
       "dev": true,
       "dependencies": {
-        "whatwg-mimetype": "^4.0.0",
-        "whatwg-url": "^14.0.0"
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
       },
       "engines": {
-        "node": ">=18"
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/data-view-byte-length": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
+      "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/data-view-byte-offset": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
+      "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.6",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/dayjs": {
@@ -4614,12 +4521,6 @@
         }
       }
     },
-    "node_modules/decimal.js": {
-      "version": "10.4.3",
-      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
-      "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
-      "dev": true
-    },
     "node_modules/decode-named-character-reference": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz",
@@ -4710,15 +4611,6 @@
         "robust-predicates": "^3.0.2"
       }
     },
-    "node_modules/delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
     "node_modules/dependency-graph": {
       "version": "0.11.0",
       "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz",
@@ -4829,9 +4721,9 @@
       }
     },
     "node_modules/dompurify": {
-      "version": "3.0.9",
-      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.9.tgz",
-      "integrity": "sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ=="
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.10.tgz",
+      "integrity": "sha512-WZDL8ZHTliEVP3Lk4phtvjg8SNQ3YMc5WVstxE8cszKZrFjzI4PF4ZTIk9VGAc9vZADO7uGO2V/ZiStcRSAT4Q=="
     },
     "node_modules/domutils": {
       "version": "3.1.0",
@@ -4874,9 +4766,9 @@
       }
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.706",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.706.tgz",
-      "integrity": "sha512-fO01fufoGd6jKK3HR8ofBapF3ZPfgxNJ/ua9xQAhFu93TwWIs4d+weDn3kje3GB4S7aGUTfk5nvdU5F7z5mF9Q=="
+      "version": "1.4.713",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.713.tgz",
+      "integrity": "sha512-vDarADhwntXiULEdmWd77g2dV6FrNGa8ecAC29MZ4TwPut2fvosD0/5sJd1qWNNe8HcJFAC+F5Lf9jW1NPtWmw=="
     },
     "node_modules/elkjs": {
       "version": "0.9.2",
@@ -4947,17 +4839,21 @@
       }
     },
     "node_modules/es-abstract": {
-      "version": "1.22.5",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz",
-      "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==",
+      "version": "1.23.2",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz",
+      "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==",
       "dev": true,
       "dependencies": {
         "array-buffer-byte-length": "^1.0.1",
         "arraybuffer.prototype.slice": "^1.0.3",
         "available-typed-arrays": "^1.0.7",
         "call-bind": "^1.0.7",
+        "data-view-buffer": "^1.0.1",
+        "data-view-byte-length": "^1.0.1",
+        "data-view-byte-offset": "^1.0.0",
         "es-define-property": "^1.0.0",
         "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
         "es-set-tostringtag": "^2.0.3",
         "es-to-primitive": "^1.2.1",
         "function.prototype.name": "^1.1.6",
@@ -4968,10 +4864,11 @@
         "has-property-descriptors": "^1.0.2",
         "has-proto": "^1.0.3",
         "has-symbols": "^1.0.3",
-        "hasown": "^2.0.1",
+        "hasown": "^2.0.2",
         "internal-slot": "^1.0.7",
         "is-array-buffer": "^3.0.4",
         "is-callable": "^1.2.7",
+        "is-data-view": "^1.0.1",
         "is-negative-zero": "^2.0.3",
         "is-regex": "^1.1.4",
         "is-shared-array-buffer": "^1.0.3",
@@ -4982,17 +4879,17 @@
         "object-keys": "^1.1.1",
         "object.assign": "^4.1.5",
         "regexp.prototype.flags": "^1.5.2",
-        "safe-array-concat": "^1.1.0",
+        "safe-array-concat": "^1.1.2",
         "safe-regex-test": "^1.0.3",
-        "string.prototype.trim": "^1.2.8",
-        "string.prototype.trimend": "^1.0.7",
+        "string.prototype.trim": "^1.2.9",
+        "string.prototype.trimend": "^1.0.8",
         "string.prototype.trimstart": "^1.0.7",
         "typed-array-buffer": "^1.0.2",
         "typed-array-byte-length": "^1.0.1",
         "typed-array-byte-offset": "^1.0.2",
         "typed-array-length": "^1.0.5",
         "unbox-primitive": "^1.0.2",
-        "which-typed-array": "^1.1.14"
+        "which-typed-array": "^1.1.15"
       },
       "engines": {
         "node": ">= 0.4"
@@ -5023,12 +4920,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/es-array-method-boxes-properly": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
-      "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
-      "dev": true
-    },
     "node_modules/es-define-property": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
@@ -5051,35 +4942,46 @@
       }
     },
     "node_modules/es-iterator-helpers": {
-      "version": "1.0.17",
-      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz",
-      "integrity": "sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==",
+      "version": "1.0.18",
+      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz",
+      "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==",
       "dev": true,
       "dependencies": {
-        "asynciterator.prototype": "^1.0.0",
         "call-bind": "^1.0.7",
         "define-properties": "^1.2.1",
-        "es-abstract": "^1.22.4",
+        "es-abstract": "^1.23.0",
         "es-errors": "^1.3.0",
-        "es-set-tostringtag": "^2.0.2",
+        "es-set-tostringtag": "^2.0.3",
         "function-bind": "^1.1.2",
         "get-intrinsic": "^1.2.4",
         "globalthis": "^1.0.3",
         "has-property-descriptors": "^1.0.2",
-        "has-proto": "^1.0.1",
+        "has-proto": "^1.0.3",
         "has-symbols": "^1.0.3",
         "internal-slot": "^1.0.7",
         "iterator.prototype": "^1.1.2",
-        "safe-array-concat": "^1.1.0"
+        "safe-array-concat": "^1.1.2"
       },
       "engines": {
         "node": ">= 0.4"
       }
     },
     "node_modules/es-module-lexer": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
-      "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w=="
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.2.tgz",
+      "integrity": "sha512-7nOqkomXZEaxUDJw21XZNtRk739QvrPSoZoRtbsEfcii00vdzZUh6zh1CQwHhrib8MdEtJfv5rJiGeb4KuV/vw=="
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+      "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
+      "dev": true,
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
     },
     "node_modules/es-set-tostringtag": {
       "version": "2.0.3",
@@ -6131,25 +6033,6 @@
         }
       }
     },
-    "node_modules/fetch-ponyfill/node_modules/tr46": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
-      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
-    },
-    "node_modules/fetch-ponyfill/node_modules/webidl-conversions": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
-      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
-    },
-    "node_modules/fetch-ponyfill/node_modules/whatwg-url": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
-      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
-      "dependencies": {
-        "tr46": "~0.0.3",
-        "webidl-conversions": "^3.0.0"
-      }
-    },
     "node_modules/file-entry-cache": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -6241,20 +6124,6 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/form-data": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
-      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
-      "dev": true,
-      "dependencies": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.8",
-        "mime-types": "^2.1.12"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/fs-extra": {
       "version": "10.1.0",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
@@ -6632,6 +6501,20 @@
         "node": ">=0.8.0"
       }
     },
+    "node_modules/happy-dom": {
+      "version": "14.2.0",
+      "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.2.0.tgz",
+      "integrity": "sha512-vTqF/9MEkRKgYy5eKq9W0uiNmkgnVAmJhRwn8x8fQBR7lc4C84859jLhgZ1lR4Gi/t70oSdgvtLpxlHjgdJrAw==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.5.0",
+        "webidl-conversions": "^7.0.0",
+        "whatwg-mimetype": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
     "node_modules/has-bigints": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
@@ -6736,18 +6619,6 @@
         "node": ">=14"
       }
     },
-    "node_modules/html-encoding-sniffer": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
-      "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
-      "dev": true,
-      "dependencies": {
-        "whatwg-encoding": "^3.1.1"
-      },
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/html-tags": {
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
@@ -6784,32 +6655,6 @@
       "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.11.tgz",
       "integrity": "sha512-WlVuICn8dfNOOgYmdYzYG8zSnP3++AdHkMHooQAzGZObWpVXYathpz/I37ycF4zikR6YduzfCvEcxk20JkIUsw=="
     },
-    "node_modules/http-proxy-agent": {
-      "version": "7.0.2",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
-      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
-      "dev": true,
-      "dependencies": {
-        "agent-base": "^7.1.0",
-        "debug": "^4.3.4"
-      },
-      "engines": {
-        "node": ">= 14"
-      }
-    },
-    "node_modules/https-proxy-agent": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
-      "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
-      "dev": true,
-      "dependencies": {
-        "agent-base": "^7.0.2",
-        "debug": "4"
-      },
-      "engines": {
-        "node": ">= 14"
-      }
-    },
     "node_modules/human-signals": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
@@ -7101,6 +6946,21 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-data-view": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
+      "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
+      "dev": true,
+      "dependencies": {
+        "is-typed-array": "^1.1.13"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/is-date-object": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
@@ -7568,55 +7428,6 @@
         "node": ">=12.0.0"
       }
     },
-    "node_modules/jsdom": {
-      "version": "24.0.0",
-      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz",
-      "integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==",
-      "dev": true,
-      "dependencies": {
-        "cssstyle": "^4.0.1",
-        "data-urls": "^5.0.0",
-        "decimal.js": "^10.4.3",
-        "form-data": "^4.0.0",
-        "html-encoding-sniffer": "^4.0.0",
-        "http-proxy-agent": "^7.0.0",
-        "https-proxy-agent": "^7.0.2",
-        "is-potential-custom-element-name": "^1.0.1",
-        "nwsapi": "^2.2.7",
-        "parse5": "^7.1.2",
-        "rrweb-cssom": "^0.6.0",
-        "saxes": "^6.0.0",
-        "symbol-tree": "^3.2.4",
-        "tough-cookie": "^4.1.3",
-        "w3c-xmlserializer": "^5.0.0",
-        "webidl-conversions": "^7.0.0",
-        "whatwg-encoding": "^3.1.1",
-        "whatwg-mimetype": "^4.0.0",
-        "whatwg-url": "^14.0.0",
-        "ws": "^8.16.0",
-        "xml-name-validator": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=18"
-      },
-      "peerDependencies": {
-        "canvas": "^2.11.2"
-      },
-      "peerDependenciesMeta": {
-        "canvas": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/jsdom/node_modules/xml-name-validator": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
-      "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
-      "dev": true,
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/jsep": {
       "version": "1.3.8",
       "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.8.tgz",
@@ -8956,25 +8767,6 @@
         }
       }
     },
-    "node_modules/node-fetch/node_modules/tr46": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
-      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
-    },
-    "node_modules/node-fetch/node_modules/webidl-conversions": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
-      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
-    },
-    "node_modules/node-fetch/node_modules/whatwg-url": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
-      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
-      "dependencies": {
-        "tr46": "~0.0.3",
-        "webidl-conversions": "^3.0.0"
-      }
-    },
     "node_modules/node-releases": {
       "version": "2.0.14",
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
@@ -9066,12 +8858,6 @@
         "url": "https://github.com/fb55/nth-check?sponsor=1"
       }
     },
-    "node_modules/nwsapi": {
-      "version": "2.2.7",
-      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
-      "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==",
-      "dev": true
-    },
     "node_modules/obj-props": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/obj-props/-/obj-props-1.4.0.tgz",
@@ -9134,28 +8920,29 @@
       }
     },
     "node_modules/object.entries": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz",
-      "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==",
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
+      "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       },
       "engines": {
         "node": ">= 0.4"
       }
     },
     "node_modules/object.fromentries": {
-      "version": "2.0.7",
-      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz",
-      "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==",
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+      "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0"
       },
       "engines": {
         "node": ">= 0.4"
@@ -9165,27 +8952,28 @@
       }
     },
     "node_modules/object.groupby": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz",
-      "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+      "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
       "dev": true,
       "dependencies": {
-        "array.prototype.filter": "^1.0.3",
-        "call-bind": "^1.0.5",
+        "call-bind": "^1.0.7",
         "define-properties": "^1.2.1",
-        "es-abstract": "^1.22.3",
-        "es-errors": "^1.0.0"
+        "es-abstract": "^1.23.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
       }
     },
     "node_modules/object.values": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz",
-      "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
+      "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       },
       "engines": {
         "node": ">= 0.4"
@@ -9311,18 +9099,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/parse5": {
-      "version": "7.1.2",
-      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
-      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
-      "dev": true,
-      "dependencies": {
-        "entities": "^4.4.0"
-      },
-      "funding": {
-        "url": "https://github.com/inikulin/parse5?sponsor=1"
-      }
-    },
     "node_modules/path-exists": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -9949,12 +9725,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/psl": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
-      "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
-      "dev": true
-    },
     "node_modules/punycode": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -9972,12 +9742,6 @@
         "node": ">=6"
       }
     },
-    "node_modules/querystringify": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
-      "dev": true
-    },
     "node_modules/queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -10156,16 +9920,16 @@
       }
     },
     "node_modules/reflect.getprototypeof": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz",
-      "integrity": "sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
+      "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.5",
+        "call-bind": "^1.0.7",
         "define-properties": "^1.2.1",
-        "es-abstract": "^1.22.3",
-        "es-errors": "^1.0.0",
-        "get-intrinsic": "^1.2.3",
+        "es-abstract": "^1.23.1",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
         "globalthis": "^1.0.3",
         "which-builtin-type": "^1.1.3"
       },
@@ -10259,12 +10023,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/requires-port": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
-      "dev": true
-    },
     "node_modules/reserved": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/reserved/-/reserved-0.1.2.tgz",
@@ -10369,12 +10127,6 @@
         "fsevents": "~2.3.2"
       }
     },
-    "node_modules/rrweb-cssom": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
-      "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
-      "dev": true
-    },
     "node_modules/run-con": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz",
@@ -10499,18 +10251,6 @@
       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
       "dev": true
     },
-    "node_modules/saxes": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
-      "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
-      "dev": true,
-      "dependencies": {
-        "xmlchars": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=v12.22.7"
-      }
-    },
     "node_modules/schema-utils": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
@@ -10720,12 +10460,12 @@
       }
     },
     "node_modules/solid-js": {
-      "version": "1.8.15",
-      "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.15.tgz",
-      "integrity": "sha512-d0QP/efr3UVcwGgWVPveQQ0IHOH6iU7yUhc2piy8arNG8wxKmvUy1kFxyF8owpmfCWGB87usDKMaVnsNYZm+Vw==",
+      "version": "1.8.16",
+      "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.16.tgz",
+      "integrity": "sha512-rja94MNU9flF3qQRLNsu60QHKBDKBkVE1DldJZPIfn2ypIn3NV2WpSbGTQIvsyGPBo+9E2IMjwqnqpbgfWuzeg==",
       "dependencies": {
         "csstype": "^3.1.0",
-        "seroval": "^1.0.3",
+        "seroval": "^1.0.4",
         "seroval-plugins": "^1.0.3"
       }
     },
@@ -10748,9 +10488,9 @@
       }
     },
     "node_modules/source-map-js": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
-      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -10904,14 +10644,15 @@
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
     },
     "node_modules/string.prototype.trim": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz",
-      "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==",
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
+      "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.0",
+        "es-object-atoms": "^1.0.0"
       },
       "engines": {
         "node": ">= 0.4"
@@ -10921,14 +10662,14 @@
       }
     },
     "node_modules/string.prototype.trimend": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz",
-      "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
+      "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -11386,12 +11127,6 @@
       "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.12.0.tgz",
       "integrity": "sha512-Rt1xUpbHulJVGbiQjq9yy9/r/0Pg6TmpcG+fXTaMePDc8z5WUw4LfaWts5qcNv/8ewPvBIbY7DKq7qReIKNCCQ=="
     },
-    "node_modules/symbol-tree": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
-      "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
-      "dev": true
-    },
     "node_modules/sync-fetch": {
       "version": "0.4.5",
       "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.5.tgz",
@@ -11724,41 +11459,10 @@
       "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz",
       "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ=="
     },
-    "node_modules/tough-cookie": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
-      "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
-      "dev": true,
-      "dependencies": {
-        "psl": "^1.1.33",
-        "punycode": "^2.1.1",
-        "universalify": "^0.2.0",
-        "url-parse": "^1.5.3"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/tough-cookie/node_modules/universalify": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
-      "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
-      "dev": true,
-      "engines": {
-        "node": ">= 4.0.0"
-      }
-    },
     "node_modules/tr46": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
-      "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
-      "dev": true,
-      "dependencies": {
-        "punycode": "^2.3.1"
-      },
-      "engines": {
-        "node": ">=18"
-      }
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
     },
     "node_modules/tributejs": {
       "version": "5.1.3",
@@ -11927,9 +11631,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.4.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
-      "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==",
+      "version": "5.4.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz",
+      "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
       "devOptional": true,
       "peer": true,
       "bin": {
@@ -11952,9 +11656,9 @@
       "dev": true
     },
     "node_modules/ufo": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz",
-      "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==",
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz",
+      "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==",
       "dev": true
     },
     "node_modules/uint8-to-base64": {
@@ -12058,16 +11762,6 @@
       "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==",
       "dev": true
     },
-    "node_modules/url-parse": {
-      "version": "1.5.10",
-      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
-      "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
-      "dev": true,
-      "dependencies": {
-        "querystringify": "^2.1.1",
-        "requires-port": "^1.0.0"
-      }
-    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -12131,14 +11825,14 @@
       }
     },
     "node_modules/vite": {
-      "version": "5.1.6",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz",
-      "integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==",
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.2.tgz",
+      "integrity": "sha512-FWZbz0oSdLq5snUI0b6sULbz58iXFXdvkZfZWR/F0ZJuKTSPO7v72QPXt6KqYeMFb0yytNp6kZosxJ96Nr/wDQ==",
       "dev": true,
       "dependencies": {
-        "esbuild": "^0.19.3",
-        "postcss": "^8.4.35",
-        "rollup": "^4.2.0"
+        "esbuild": "^0.20.1",
+        "postcss": "^8.4.36",
+        "rollup": "^4.13.0"
       },
       "bin": {
         "vite": "bin/vite.js"
@@ -12213,418 +11907,12 @@
       "integrity": "sha512-KRCIFX3PWVUuEjpi9O7EKLT9E27OqOA3RimIvVx6cziLAUxvnk2VvHQfMrP+mKkqyqqSmnnYyTig3OyDnK/zlA==",
       "dev": true
     },
-    "node_modules/vite/node_modules/@esbuild/aix-ppc64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
-      "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "aix"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/android-arm": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
-      "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/android-arm64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
-      "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/android-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
-      "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
-      "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/darwin-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
-      "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
-      "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
-      "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-arm": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
-      "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-arm64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
-      "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-ia32": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
-      "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-loong64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
-      "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
-      "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
-      "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
-      "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-s390x": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
-      "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/linux-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
-      "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
-      "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
-      "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/sunos-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
-      "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/win32-arm64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
-      "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/win32-ia32": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
-      "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/vite/node_modules/@esbuild/win32-x64": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
-      "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=12"
-      }
-    },
     "node_modules/vite/node_modules/@types/estree": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
       "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
       "dev": true
     },
-    "node_modules/vite/node_modules/esbuild": {
-      "version": "0.19.12",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
-      "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
-      "dev": true,
-      "hasInstallScript": true,
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.19.12",
-        "@esbuild/android-arm": "0.19.12",
-        "@esbuild/android-arm64": "0.19.12",
-        "@esbuild/android-x64": "0.19.12",
-        "@esbuild/darwin-arm64": "0.19.12",
-        "@esbuild/darwin-x64": "0.19.12",
-        "@esbuild/freebsd-arm64": "0.19.12",
-        "@esbuild/freebsd-x64": "0.19.12",
-        "@esbuild/linux-arm": "0.19.12",
-        "@esbuild/linux-arm64": "0.19.12",
-        "@esbuild/linux-ia32": "0.19.12",
-        "@esbuild/linux-loong64": "0.19.12",
-        "@esbuild/linux-mips64el": "0.19.12",
-        "@esbuild/linux-ppc64": "0.19.12",
-        "@esbuild/linux-riscv64": "0.19.12",
-        "@esbuild/linux-s390x": "0.19.12",
-        "@esbuild/linux-x64": "0.19.12",
-        "@esbuild/netbsd-x64": "0.19.12",
-        "@esbuild/openbsd-x64": "0.19.12",
-        "@esbuild/sunos-x64": "0.19.12",
-        "@esbuild/win32-arm64": "0.19.12",
-        "@esbuild/win32-ia32": "0.19.12",
-        "@esbuild/win32-x64": "0.19.12"
-      }
-    },
     "node_modules/vite/node_modules/fsevents": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -12639,6 +11927,34 @@
         "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
       }
     },
+    "node_modules/vite/node_modules/postcss": {
+      "version": "8.4.38",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.7",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.2.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
     "node_modules/vite/node_modules/rollup": {
       "version": "4.13.0",
       "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
@@ -12843,27 +12159,6 @@
         "vue": "^3.2.29"
       }
     },
-    "node_modules/w3c-xmlserializer": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
-      "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
-      "dev": true,
-      "dependencies": {
-        "xml-name-validator": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
-      "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
-      "dev": true,
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/watchpack": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
@@ -13088,40 +12383,29 @@
         "node": ">=10.13.0"
       }
     },
-    "node_modules/whatwg-encoding": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
-      "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
-      "dev": true,
-      "dependencies": {
-        "iconv-lite": "0.6.3"
-      },
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/whatwg-mimetype": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
-      "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
+      "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
       "dev": true,
       "engines": {
-        "node": ">=18"
+        "node": ">=12"
       }
     },
     "node_modules/whatwg-url": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
-      "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
-      "dev": true,
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
       "dependencies": {
-        "tr46": "^5.0.0",
-        "webidl-conversions": "^7.0.0"
-      },
-      "engines": {
-        "node": ">=18"
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
       }
     },
+    "node_modules/whatwg-url/node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -13344,27 +12628,6 @@
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
-    "node_modules/ws": {
-      "version": "8.16.0",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
-      "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=10.0.0"
-      },
-      "peerDependencies": {
-        "bufferutil": "^4.0.1",
-        "utf-8-validate": ">=5.0.2"
-      },
-      "peerDependenciesMeta": {
-        "bufferutil": {
-          "optional": true
-        },
-        "utf-8-validate": {
-          "optional": true
-        }
-      }
-    },
     "node_modules/xml-name-validator": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
@@ -13374,12 +12637,6 @@
         "node": ">=12"
       }
     },
-    "node_modules/xmlchars": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
-      "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
-      "dev": true
-    },
     "node_modules/y18n": {
       "version": "5.0.8",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index b8594e8b3..77a58dacf 100644
--- a/package.json
+++ b/package.json
@@ -84,7 +84,7 @@
     "eslint-plugin-vue": "9.23.0",
     "eslint-plugin-vue-scoped-css": "2.7.2",
     "eslint-plugin-wc": "2.0.4",
-    "jsdom": "24.0.0",
+    "happy-dom": "14.2.0",
     "markdownlint-cli": "0.39.0",
     "postcss-html": "1.6.0",
     "stylelint": "16.2.1",
diff --git a/playwright.config.js b/playwright.config.js
index 6595bc431..fdf6514f2 100644
--- a/playwright.config.js
+++ b/playwright.config.js
@@ -27,7 +27,7 @@ export default {
      * Maximum time expect() should wait for the condition to be met.
      * For example in `await expect(locator).toHaveText();`
      */
-    timeout: 2000
+    timeout: 2000,
   },
 
   /* Fail the build on CI if you accidentally left test.only in the source code. */
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 843da5513..2640819a5 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -874,10 +874,11 @@ func EditIssue(ctx *context.APIContext) {
 	}
 	if form.State != nil {
 		if issue.IsPull {
-			if pr, err := issue.GetPullRequest(ctx); err != nil {
+			if err := issue.LoadPullRequest(ctx); err != nil {
 				ctx.Error(http.StatusInternalServerError, "GetPullRequest", err)
 				return
-			} else if pr.HasMerged {
+			}
+			if issue.PullRequest.HasMerged {
 				ctx.Error(http.StatusPreconditionFailed, "MergedPRState", "cannot change state of this pull request, it was already merged")
 				return
 			}
diff --git a/routers/api/v1/repo/issue_pin.go b/routers/api/v1/repo/issue_pin.go
index ff1135862..8fcf670fd 100644
--- a/routers/api/v1/repo/issue_pin.go
+++ b/routers/api/v1/repo/issue_pin.go
@@ -240,18 +240,12 @@ func ListPinnedPullRequests(ctx *context.APIContext) {
 	}
 
 	apiPrs := make([]*api.PullRequest, len(issues))
+	if err := issues.LoadPullRequests(ctx); err != nil {
+		ctx.Error(http.StatusInternalServerError, "LoadPullRequests", err)
+		return
+	}
 	for i, currentIssue := range issues {
-		pr, err := currentIssue.GetPullRequest(ctx)
-		if err != nil {
-			ctx.Error(http.StatusInternalServerError, "GetPullRequest", err)
-			return
-		}
-
-		if err = pr.LoadIssue(ctx); err != nil {
-			ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
-			return
-		}
-
+		pr := currentIssue.PullRequest
 		if err = pr.LoadAttributes(ctx); err != nil {
 			ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
 			return
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index c2d86541b..eec3c49bc 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -21,6 +21,7 @@ import (
 	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unit"
 	user_model "code.gitea.io/gitea/models/user"
+	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/gitrepo"
 	"code.gitea.io/gitea/modules/log"
@@ -96,13 +97,17 @@ func ListPullRequests(ctx *context.APIContext) {
 	//   "404":
 	//     "$ref": "#/responses/notFound"
 
+	labelIDs, err := base.StringsToInt64s(ctx.FormStrings("labels"))
+	if err != nil {
+		ctx.Error(http.StatusInternalServerError, "PullRequests", err)
+		return
+	}
 	listOptions := utils.GetListOptions(ctx)
-
 	prs, maxResults, err := issues_model.PullRequests(ctx, ctx.Repo.Repository.ID, &issues_model.PullRequestsOptions{
 		ListOptions: listOptions,
 		State:       ctx.FormTrim("state"),
 		SortType:    ctx.FormTrim("sort"),
-		Labels:      ctx.FormStrings("labels"),
+		Labels:      labelIDs,
 		MilestoneID: ctx.FormInt64("milestone"),
 	})
 	if err != nil {
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index f5527cb15..fff47caa8 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -75,6 +75,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
 			updates = append(updates, option)
 			if repo.IsEmpty && (refFullName.BranchName() == "master" || refFullName.BranchName() == "main") {
 				// put the master/main branch first
+				// FIXME: It doesn't always work, since the master/main branch may not be the first batch of updates.
+				//        If the user pushes many branches at once, the Git hook will call the internal API in batches, rather than all at once.
+				//        See https://github.com/go-gitea/gitea/blob/cb52b17f92e2d2293f7c003649743464492bca48/cmd/hook.go#L27
+				//        If the user executes `git push origin --all` and pushes more than 30 branches, the master/main may not be the default branch.
 				copy(updates[1:], updates)
 				updates[0] = option
 			}
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index 6dfcfc3d9..b93668c5a 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -275,9 +275,7 @@ func ViewUser(ctx *context.Context) {
 	}
 
 	repos, count, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		ListOptions: db.ListOptionsAll,
 		OwnerID:     u.ID,
 		OrderBy:     db.SearchOrderByAlphabetically,
 		Private:     true,
@@ -300,9 +298,7 @@ func ViewUser(ctx *context.Context) {
 	ctx.Data["EmailsTotal"] = len(emails)
 
 	orgs, err := db.Find[org_model.Organization](ctx, org_model.FindOrgOptions{
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		ListOptions:    db.ListOptionsAll,
 		UserID:         u.ID,
 		IncludePrivate: true,
 	})
diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go
index f27329aa0..6059ad141 100644
--- a/routers/web/repo/actions/actions.go
+++ b/routers/web/repo/actions/actions.go
@@ -104,8 +104,13 @@ func List(ctx *context.Context) {
 				workflows = append(workflows, workflow)
 				continue
 			}
-			// Check whether have matching runner
+			// The workflow must contain at least one job without "needs". Otherwise, a deadlock will occur and no jobs will be able to run.
+			hasJobWithoutNeeds := false
+			// Check whether have matching runner and a job without "needs"
 			for _, j := range wf.Jobs {
+				if !hasJobWithoutNeeds && len(j.Needs()) == 0 {
+					hasJobWithoutNeeds = true
+				}
 				runsOnList := j.RunsOn()
 				for _, ro := range runsOnList {
 					if strings.Contains(ro, "${{") {
@@ -123,6 +128,9 @@ func List(ctx *context.Context) {
 					break
 				}
 			}
+			if !hasJobWithoutNeeds {
+				workflow.ErrMsg = ctx.Locale.TrString("actions.runs.no_job_without_needs")
+			}
 			workflows = append(workflows, workflow)
 		}
 	}
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 23ce70a15..fa687bbb9 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -353,12 +353,25 @@ func Rerun(ctx *context_module.Context) {
 		return
 	}
 
-	if jobIndexStr != "" {
-		jobs = []*actions_model.ActionRunJob{job}
+	if jobIndexStr == "" { // rerun all jobs
+		for _, j := range jobs {
+			// if the job has needs, it should be set to "blocked" status to wait for other jobs
+			shouldBlock := len(j.Needs) > 0
+			if err := rerunJob(ctx, j, shouldBlock); err != nil {
+				ctx.Error(http.StatusInternalServerError, err.Error())
+				return
+			}
+		}
+		ctx.JSON(http.StatusOK, struct{}{})
+		return
 	}
 
-	for _, j := range jobs {
-		if err := rerunJob(ctx, j); err != nil {
+	rerunJobs := actions_service.GetAllRerunJobs(job, jobs)
+
+	for _, j := range rerunJobs {
+		// jobs other than the specified one should be set to "blocked" status
+		shouldBlock := j.JobID != job.JobID
+		if err := rerunJob(ctx, j, shouldBlock); err != nil {
 			ctx.Error(http.StatusInternalServerError, err.Error())
 			return
 		}
@@ -367,7 +380,7 @@ func Rerun(ctx *context_module.Context) {
 	ctx.JSON(http.StatusOK, struct{}{})
 }
 
-func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) error {
+func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob, shouldBlock bool) error {
 	status := job.Status
 	if !status.IsDone() {
 		return nil
@@ -375,6 +388,9 @@ func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) erro
 
 	job.TaskID = 0
 	job.Status = actions_model.StatusWaiting
+	if shouldBlock {
+		job.Status = actions_model.StatusBlocked
+	}
 	job.Started = 0
 	job.Stopped = 0
 
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index 0c585a93b..718454e06 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -367,7 +367,7 @@ func Diff(ctx *context.Context) {
 	ctx.Data["Commit"] = commit
 	ctx.Data["Diff"] = diff
 
-	statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptions{ListAll: true})
+	statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll)
 	if err != nil {
 		log.Error("GetLatestCommitStatus: %v", err)
 	}
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index b0570f97c..cfb0e859b 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -697,10 +697,8 @@ func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repositor
 	defer gitRepo.Close()
 
 	branches, err = git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
-		RepoID: repo.ID,
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		RepoID:          repo.ID,
+		ListOptions:     db.ListOptionsAll,
 		IsDeletedBranch: optional.Some(false),
 	})
 	if err != nil {
@@ -754,10 +752,8 @@ func CompareDiff(ctx *context.Context) {
 	}
 
 	headBranches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
-		RepoID: ci.HeadRepo.ID,
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		RepoID:          ci.HeadRepo.ID,
+		ListOptions:     db.ListOptionsAll,
 		IsDeletedBranch: optional.Some(false),
 	})
 	if err != nil {
@@ -980,5 +976,8 @@ func getExcerptLines(commit *git.Commit, filePath string, idxLeft, idxRight, chu
 		}
 		diffLines = append(diffLines, diffLine)
 	}
+	if err = scanner.Err(); err != nil {
+		return nil, fmt.Errorf("getExcerptLines scan: %w", err)
+	}
 	return diffLines, nil
 }
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 4f26c0c52..ea0c8ddb7 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -374,9 +374,9 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
 				ctx.Error(http.StatusInternalServerError, err.Error())
 			}
 		} else if models.IsErrCommitIDDoesNotMatch(err) {
-			ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(ctx.Repo.CommitID)), tplEditFile, &form)
+			ctx.RenderWithErr(ctx.Tr("repo.editor.commit_id_not_matching"), tplEditFile, &form)
 		} else if git.IsErrPushOutOfDate(err) {
-			ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(form.NewBranchName)), tplEditFile, &form)
+			ctx.RenderWithErr(ctx.Tr("repo.editor.push_out_of_date"), tplEditFile, &form)
 		} else if git.IsErrPushRejected(err) {
 			errPushRej := err.(*git.ErrPushRejected)
 			if len(errPushRej.Message) == 0 {
diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go
index 07b372279..9da4237c1 100644
--- a/routers/web/repo/find.go
+++ b/routers/web/repo/find.go
@@ -7,6 +7,7 @@ import (
 	"net/http"
 
 	"code.gitea.io/gitea/modules/base"
+	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/services/context"
 )
 
@@ -17,7 +18,7 @@ const (
 // FindFiles render the page to find repository files
 func FindFiles(ctx *context.Context) {
 	path := ctx.Params("*")
-	ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + path
-	ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + path
+	ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + util.PathEscapeSegments(path)
+	ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path)
 	ctx.HTML(http.StatusOK, tplFindFiles)
 }
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index e4193e9b7..c0ec12133 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -192,8 +192,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
 	if len(selectLabels) > 0 {
 		labelIDs, err = base.StringsToInt64s(strings.Split(selectLabels, ","))
 		if err != nil {
-			ctx.ServerError("StringsToInt64s", err)
-			return
+			ctx.Flash.Error(ctx.Tr("invalid_data", selectLabels), true)
 		}
 	}
 
@@ -451,13 +450,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
 	linkStr := "%s?q=%s&type=%s&sort=%s&state=%s&labels=%s&milestone=%d&project=%d&assignee=%d&poster=%d&archived=%t"
 	ctx.Data["AllStatesLink"] = fmt.Sprintf(linkStr, ctx.Link,
 		url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "all", url.QueryEscape(selectLabels),
-		mentionedID, projectID, assigneeID, posterID, archived)
+		milestoneID, projectID, assigneeID, posterID, archived)
 	ctx.Data["OpenLink"] = fmt.Sprintf(linkStr, ctx.Link,
 		url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "open", url.QueryEscape(selectLabels),
-		mentionedID, projectID, assigneeID, posterID, archived)
+		milestoneID, projectID, assigneeID, posterID, archived)
 	ctx.Data["ClosedLink"] = fmt.Sprintf(linkStr, ctx.Link,
 		url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "closed", url.QueryEscape(selectLabels),
-		mentionedID, projectID, assigneeID, posterID, archived)
+		milestoneID, projectID, assigneeID, posterID, archived)
 	ctx.Data["SelLabelIDs"] = labelIDs
 	ctx.Data["SelectLabels"] = selectLabels
 	ctx.Data["ViewType"] = viewType
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 8727f3d1e..c6c614253 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -505,7 +505,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
 
 	if len(compareInfo.Commits) != 0 {
 		sha := compareInfo.Commits[0].ID.String()
-		commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptions{ListAll: true})
+		commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptionsAll)
 		if err != nil {
 			ctx.ServerError("GetLatestCommitStatus", err)
 			return nil
@@ -567,7 +567,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
 			ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err)
 			return nil
 		}
-		commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{ListAll: true})
+		commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll)
 		if err != nil {
 			ctx.ServerError("GetLatestCommitStatus", err)
 			return nil
@@ -659,7 +659,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
 		return nil
 	}
 
-	commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{ListAll: true})
+	commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll)
 	if err != nil {
 		ctx.ServerError("GetLatestCommitStatus", err)
 		return nil
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index 95447a8f5..38bb1305f 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -136,7 +136,7 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions)
 		}
 
 		if canReadActions {
-			statuses, _, err := git_model.GetLatestCommitStatus(ctx, r.Repo.ID, r.Sha1, db.ListOptions{ListAll: true})
+			statuses, _, err := git_model.GetLatestCommitStatus(ctx, r.Repo.ID, r.Sha1, db.ListOptionsAll)
 			if err != nil {
 				return nil, err
 			}
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index 07e6c937b..b2458a561 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -618,26 +618,31 @@ func SearchRepo(ctx *context.Context) {
 		}
 	}
 
-	var err error
+	// To improve performance when only the count is requested
+	if ctx.FormBool("count_only") {
+		if count, err := repo_model.CountRepository(ctx, opts); err != nil {
+			log.Error("CountRepository: %v", err)
+			ctx.JSON(http.StatusInternalServerError, nil) // frontend JS doesn't handle error response (same as below)
+		} else {
+			ctx.SetTotalCountHeader(count)
+			ctx.JSONOK()
+		}
+		return
+	}
+
 	repos, count, err := repo_model.SearchRepository(ctx, opts)
 	if err != nil {
-		ctx.JSON(http.StatusInternalServerError, api.SearchError{
-			OK:    false,
-			Error: err.Error(),
-		})
+		log.Error("SearchRepository: %v", err)
+		ctx.JSON(http.StatusInternalServerError, nil)
 		return
 	}
 
 	ctx.SetTotalCountHeader(count)
 
-	// To improve performance when only the count is requested
-	if ctx.FormBool("count_only") {
-		return
-	}
-
 	latestCommitStatuses, err := commitstatus_service.FindReposLastestCommitStatuses(ctx, repos)
 	if err != nil {
 		log.Error("FindReposLastestCommitStatuses: %v", err)
+		ctx.JSON(http.StatusInternalServerError, nil)
 		return
 	}
 
@@ -679,9 +684,7 @@ func GetBranchesList(ctx *context.Context) {
 	branchOpts := git_model.FindBranchOptions{
 		RepoID:          ctx.Repo.Repository.ID,
 		IsDeletedBranch: optional.Some(false),
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		ListOptions:     db.ListOptionsAll,
 	}
 	branches, err := git_model.FindBranchNames(ctx, branchOpts)
 	if err != nil {
@@ -714,9 +717,7 @@ func PrepareBranchList(ctx *context.Context) {
 	branchOpts := git_model.FindBranchOptions{
 		RepoID:          ctx.Repo.Repository.ID,
 		IsDeletedBranch: optional.Some(false),
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		ListOptions:     db.ListOptionsAll,
 	}
 	brs, err := git_model.FindBranchNames(ctx, branchOpts)
 	if err != nil {
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 8ddfd92aa..e4d7179f6 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -364,7 +364,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
 		ctx.Data["LatestCommitVerification"] = verification
 		ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(ctx, latestCommit)
 
-		statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptions{ListAll: true})
+		statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptionsAll)
 		if err != nil {
 			log.Error("GetLatestCommitStatus: %v", err)
 		}
diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go
index f007772d6..7d0b34cb7 100644
--- a/routers/web/shared/user/header.go
+++ b/routers/web/shared/user/header.go
@@ -16,6 +16,8 @@ import (
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/gitrepo"
 	"code.gitea.io/gitea/modules/log"
+	"code.gitea.io/gitea/modules/markup"
+	"code.gitea.io/gitea/modules/markup/markdown"
 	"code.gitea.io/gitea/modules/optional"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/services/context"
@@ -35,6 +37,7 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) {
 	prepareContextForCommonProfile(ctx)
 
 	ctx.Data["IsBlocked"] = ctx.Doer != nil && user_model.IsBlocked(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
+	ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
 	ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate
 	if setting.Service.UserLocationMapURL != "" {
 		ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location)
@@ -46,6 +49,17 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) {
 		return
 	}
 	ctx.Data["OpenIDs"] = openIDs
+	if len(ctx.ContextUser.Description) != 0 {
+		content, err := markdown.RenderString(&markup.RenderContext{
+			Metas: map[string]string{"mode": "document"},
+			Ctx:   ctx,
+		}, ctx.ContextUser.Description)
+		if err != nil {
+			ctx.ServerError("RenderString", err)
+			return
+		}
+		ctx.Data["RenderedDescription"] = content
+	}
 
 	showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
 	orgs, err := db.Find[organization.Organization](ctx, organization.FindOrgOptions{
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index e58fb9513..f122dc5d9 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -529,17 +529,14 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
 
 	// Get IDs for labels (a filter option for issues/pulls).
 	// Required for IssuesOptions.
-	var labelIDs []int64
 	selectedLabels := ctx.FormString("labels")
 	if len(selectedLabels) > 0 && selectedLabels != "0" {
 		var err error
-		labelIDs, err = base.StringsToInt64s(strings.Split(selectedLabels, ","))
+		opts.LabelIDs, err = base.StringsToInt64s(strings.Split(selectedLabels, ","))
 		if err != nil {
-			ctx.ServerError("StringsToInt64s", err)
-			return
+			ctx.Flash.Error(ctx.Tr("invalid_data", selectedLabels), true)
 		}
 	}
-	opts.LabelIDs = labelIDs
 
 	// ------------------------------
 	// Get issues as defined by opts.
diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go
index 324205ed9..2105cfe5c 100644
--- a/routers/web/user/notification.go
+++ b/routers/web/user/notification.go
@@ -144,6 +144,12 @@ func getNotifications(ctx *context.Context) {
 		ctx.ServerError("LoadIssues", err)
 		return
 	}
+
+	if err = notifications.LoadIssuePullRequests(ctx); err != nil {
+		ctx.ServerError("LoadIssuePullRequests", err)
+		return
+	}
+
 	notifications = notifications.Without(failures)
 	failCount += len(failures)
 
@@ -262,8 +268,7 @@ func NotificationSubscriptions(ctx *context.Context) {
 		var err error
 		labelIDs, err = base.StringsToInt64s(strings.Split(selectedLabels, ","))
 		if err != nil {
-			ctx.ServerError("StringsToInt64s", err)
-			return
+			ctx.Flash.Error(ctx.Tr("invalid_data", selectedLabels), true)
 		}
 	}
 
diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go
index edd1fd156..423655392 100644
--- a/services/actions/commit_status.go
+++ b/services/actions/commit_status.go
@@ -79,7 +79,7 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
 	}
 	ctxname := fmt.Sprintf("%s / %s (%s)", runName, job.Name, event)
 	state := toCommitStatus(job.Status)
-	if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{ListAll: true}); err == nil {
+	if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll); err == nil {
 		for _, v := range statuses {
 			if v.Context == ctxname {
 				if v.State == state {
diff --git a/services/actions/notifier.go b/services/actions/notifier.go
index aa88d4e0d..eec5f814d 100644
--- a/services/actions/notifier.go
+++ b/services/actions/notifier.go
@@ -515,6 +515,12 @@ func (*actionsNotifier) MergePullRequest(ctx context.Context, doer *user_model.U
 }
 
 func (n *actionsNotifier) PushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
+	commitID, _ := git.NewIDFromString(opts.NewCommitID)
+	if commitID.IsZero() {
+		log.Trace("new commitID is empty")
+		return
+	}
+
 	ctx = withMethod(ctx, "PushCommits")
 
 	apiPusher := convert.ToUser(ctx, pusher, nil)
@@ -547,9 +553,9 @@ func (n *actionsNotifier) CreateRef(ctx context.Context, pusher *user_model.User
 	apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeNone})
 
 	newNotifyInput(repo, pusher, webhook_module.HookEventCreate).
-		WithRef(refFullName.ShortName()). // FIXME: should we use a full ref name
+		WithRef(refFullName.String()).
 		WithPayload(&api.CreatePayload{
-			Ref:     refFullName.ShortName(),
+			Ref:     refFullName.String(),
 			Sha:     refID,
 			RefType: refFullName.RefType(),
 			Repo:    apiRepo,
@@ -566,7 +572,7 @@ func (n *actionsNotifier) DeleteRef(ctx context.Context, pusher *user_model.User
 
 	newNotifyInput(repo, pusher, webhook_module.HookEventDelete).
 		WithPayload(&api.DeletePayload{
-			Ref:        refFullName.ShortName(),
+			Ref:        refFullName.String(),
 			RefType:    refFullName.RefType(),
 			PusherType: api.PusherTypeUser,
 			Repo:       apiRepo,
@@ -623,6 +629,10 @@ func (n *actionsNotifier) UpdateRelease(ctx context.Context, doer *user_model.Us
 }
 
 func (n *actionsNotifier) DeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) {
+	if rel.IsTag {
+		// has sent same action in `PushCommits`, so skip it.
+		return
+	}
 	ctx = withMethod(ctx, "DeleteRelease")
 	notifyRelease(ctx, doer, rel, api.HookReleaseDeleted)
 }
diff --git a/services/actions/rerun.go b/services/actions/rerun.go
new file mode 100644
index 000000000..60f665090
--- /dev/null
+++ b/services/actions/rerun.go
@@ -0,0 +1,38 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+	actions_model "code.gitea.io/gitea/models/actions"
+	"code.gitea.io/gitea/modules/container"
+)
+
+// GetAllRerunJobs get all jobs that need to be rerun when job should be rerun
+func GetAllRerunJobs(job *actions_model.ActionRunJob, allJobs []*actions_model.ActionRunJob) []*actions_model.ActionRunJob {
+	rerunJobs := []*actions_model.ActionRunJob{job}
+	rerunJobsIDSet := make(container.Set[string])
+	rerunJobsIDSet.Add(job.JobID)
+
+	for {
+		found := false
+		for _, j := range allJobs {
+			if rerunJobsIDSet.Contains(j.JobID) {
+				continue
+			}
+			for _, need := range j.Needs {
+				if rerunJobsIDSet.Contains(need) {
+					found = true
+					rerunJobs = append(rerunJobs, j)
+					rerunJobsIDSet.Add(j.JobID)
+					break
+				}
+			}
+		}
+		if !found {
+			break
+		}
+	}
+
+	return rerunJobs
+}
diff --git a/services/actions/rerun_test.go b/services/actions/rerun_test.go
new file mode 100644
index 000000000..a98de7b78
--- /dev/null
+++ b/services/actions/rerun_test.go
@@ -0,0 +1,48 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+	"testing"
+
+	actions_model "code.gitea.io/gitea/models/actions"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGetAllRerunJobs(t *testing.T) {
+	job1 := &actions_model.ActionRunJob{JobID: "job1"}
+	job2 := &actions_model.ActionRunJob{JobID: "job2", Needs: []string{"job1"}}
+	job3 := &actions_model.ActionRunJob{JobID: "job3", Needs: []string{"job2"}}
+	job4 := &actions_model.ActionRunJob{JobID: "job4", Needs: []string{"job2", "job3"}}
+
+	jobs := []*actions_model.ActionRunJob{job1, job2, job3, job4}
+
+	testCases := []struct {
+		job       *actions_model.ActionRunJob
+		rerunJobs []*actions_model.ActionRunJob
+	}{
+		{
+			job1,
+			[]*actions_model.ActionRunJob{job1, job2, job3, job4},
+		},
+		{
+			job2,
+			[]*actions_model.ActionRunJob{job2, job3, job4},
+		},
+		{
+			job3,
+			[]*actions_model.ActionRunJob{job3, job4},
+		},
+		{
+			job4,
+			[]*actions_model.ActionRunJob{job4},
+		},
+	}
+
+	for _, tc := range testCases {
+		rerunJobs := GetAllRerunJobs(tc.job, jobs)
+		assert.ElementsMatch(t, tc.rerunJobs, rerunJobs)
+	}
+}
diff --git a/services/auth/session.go b/services/auth/session.go
index d13813dcb..35d97e42d 100644
--- a/services/auth/session.go
+++ b/services/auth/session.go
@@ -4,7 +4,6 @@
 package auth
 
 import (
-	"context"
 	"net/http"
 
 	user_model "code.gitea.io/gitea/models/user"
@@ -29,40 +28,33 @@ func (s *Session) Name() string {
 // object for that uid.
 // Returns nil if there is no user uid stored in the session.
 func (s *Session) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
-	user := SessionUser(req.Context(), sess)
-	if user != nil {
-		return user, nil
-	}
-	return nil, nil
-}
-
-// SessionUser returns the user object corresponding to the "uid" session variable.
-func SessionUser(ctx context.Context, sess SessionStore) *user_model.User {
 	if sess == nil {
-		return nil
+		return nil, nil
 	}
 
 	// Get user ID
 	uid := sess.Get("uid")
 	if uid == nil {
-		return nil
+		return nil, nil
 	}
 	log.Trace("Session Authorization: Found user[%d]", uid)
 
 	id, ok := uid.(int64)
 	if !ok {
-		return nil
+		return nil, nil
 	}
 
 	// Get user object
-	user, err := user_model.GetUserByID(ctx, id)
+	user, err := user_model.GetUserByID(req.Context(), id)
 	if err != nil {
 		if !user_model.IsErrUserNotExist(err) {
-			log.Error("GetUserById: %v", err)
+			log.Error("GetUserByID: %v", err)
+			// Return the err as-is to keep current signed-in session, in case the err is something like context.Canceled. Otherwise non-existing user (nil, nil) will make the caller clear the signed-in session.
+			return nil, err
 		}
-		return nil
+		return nil, nil
 	}
 
 	log.Trace("Session Authorization: Logged in user %-v", user)
-	return user
+	return user, nil
 }
diff --git a/services/convert/notification.go b/services/convert/notification.go
index 0b97530d8..41063cf39 100644
--- a/services/convert/notification.go
+++ b/services/convert/notification.go
@@ -61,8 +61,9 @@ func ToNotificationThread(ctx context.Context, n *activities_model.Notification)
 				result.Subject.LatestCommentHTMLURL = comment.HTMLURL(ctx)
 			}
 
-			pr, _ := n.Issue.GetPullRequest(ctx)
-			if pr != nil && pr.HasMerged {
+			if err := n.Issue.LoadPullRequest(ctx); err == nil &&
+				n.Issue.PullRequest != nil &&
+				n.Issue.PullRequest.HasMerged {
 				result.Subject.State = "merged"
 			}
 		}
diff --git a/services/doctor/authorizedkeys.go b/services/doctor/authorizedkeys.go
index 050a4e797..eb6dec613 100644
--- a/services/doctor/authorizedkeys.go
+++ b/services/doctor/authorizedkeys.go
@@ -50,7 +50,11 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
 		}
 		linesInAuthorizedKeys.Add(line)
 	}
-	f.Close()
+	if err = scanner.Err(); err != nil {
+		return fmt.Errorf("scan: %w", err)
+	}
+	// although there is a "defer close" above, here close explicitly before the generating, because it needs to open the file for writing again
+	_ = f.Close()
 
 	// now we regenerate and check if there are any lines missing
 	regenerated := &bytes.Buffer{}
diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go
index cb6312346..0d4763a83 100644
--- a/services/pull/commit_status.go
+++ b/services/pull/commit_status.go
@@ -153,7 +153,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR
 		return "", fmt.Errorf("LoadBaseRepo: %w", err)
 	}
 
-	commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptions{ListAll: true})
+	commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll)
 	if err != nil {
 		return "", fmt.Errorf("GetLatestCommitStatus: %w", err)
 	}
diff --git a/services/pull/pull.go b/services/pull/pull.go
index 29a49fb4d..23a75e292 100644
--- a/services/pull/pull.go
+++ b/services/pull/pull.go
@@ -893,7 +893,7 @@ func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues
 		return nil, nil, shaErr
 	}
 
-	statuses, _, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptions{ListAll: true})
+	statuses, _, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll)
 	lastStatus = git_model.CalcCommitStatus(statuses)
 	return statuses, lastStatus, err
 }
diff --git a/services/pull/review.go b/services/pull/review.go
index 1220d5472..7d698a14f 100644
--- a/services/pull/review.go
+++ b/services/pull/review.go
@@ -52,9 +52,7 @@ func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestLis
 	issueIDs := prs.GetIssueIDs()
 
 	codeComments, err := db.Find[issues_model.Comment](ctx, issues_model.FindCommentsOptions{
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		ListOptions: db.ListOptionsAll,
 		Type:        issues_model.CommentTypeCode,
 		Invalidated: optional.Some(false),
 		IssueIDs:    issueIDs,
@@ -268,11 +266,11 @@ func CreateCodeCommentKnownReviewID(ctx context.Context, doer *user_model.User,
 
 // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
 func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repository, issue *issues_model.Issue, reviewType issues_model.ReviewType, content, commitID string, attachmentUUIDs []string) (*issues_model.Review, *issues_model.Comment, error) {
-	pr, err := issue.GetPullRequest(ctx)
-	if err != nil {
+	if err := issue.LoadPullRequest(ctx); err != nil {
 		return nil, nil, err
 	}
 
+	pr := issue.PullRequest
 	var stale bool
 	if reviewType != issues_model.ReviewTypeApprove && reviewType != issues_model.ReviewTypeReject {
 		stale = false
@@ -322,12 +320,10 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos
 // DismissApprovalReviews dismiss all approval reviews because of new commits
 func DismissApprovalReviews(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest) error {
 	reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
-		IssueID:   pull.IssueID,
-		Type:      issues_model.ReviewTypeApprove,
-		Dismissed: optional.Some(false),
+		ListOptions: db.ListOptionsAll,
+		IssueID:     pull.IssueID,
+		Type:        issues_model.ReviewTypeApprove,
+		Dismissed:   optional.Some(false),
 	})
 	if err != nil {
 		return err
diff --git a/services/repository/adopt.go b/services/repository/adopt.go
index 0ac3c774b..b337eac38 100644
--- a/services/repository/adopt.go
+++ b/services/repository/adopt.go
@@ -144,10 +144,8 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r
 	}
 
 	branches, _ := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
-		RepoID: repo.ID,
-		ListOptions: db.ListOptions{
-			ListAll: true,
-		},
+		RepoID:          repo.ID,
+		ListOptions:     db.ListOptionsAll,
 		IsDeletedBranch: optional.Some(false),
 	})
 
diff --git a/services/repository/branch.go b/services/repository/branch.go
index b68355324..64d8eda4e 100644
--- a/services/repository/branch.go
+++ b/services/repository/branch.go
@@ -127,10 +127,7 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g
 	p := protectedBranches.GetFirstMatched(branchName)
 	isProtected := p != nil
 
-	divergence := &git.DivergeObject{
-		Ahead:  -1,
-		Behind: -1,
-	}
+	var divergence *git.DivergeObject
 
 	// it's not default branch
 	if repo.DefaultBranch != dbBranch.Name && !dbBranch.IsDeleted {
@@ -141,6 +138,11 @@ func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *g
 		}
 	}
 
+	if divergence == nil {
+		// tolerate the error that we cannot get divergence
+		divergence = &git.DivergeObject{Ahead: -1, Behind: -1}
+	}
+
 	pr, err := issues_model.GetLatestPullRequestByHeadInfo(ctx, repo.ID, branchName)
 	if err != nil {
 		return nil, fmt.Errorf("GetLatestPullRequestByHeadInfo: %v", err)
diff --git a/services/webhook/telegram.go b/services/webhook/telegram.go
index e4a5b5a42..c2b482003 100644
--- a/services/webhook/telegram.go
+++ b/services/webhook/telegram.go
@@ -181,7 +181,9 @@ func (t telegramConvertor) Package(p *api.PackagePayload) (TelegramPayload, erro
 
 func createTelegramPayload(message string) TelegramPayload {
 	return TelegramPayload{
-		Message: strings.TrimSpace(message),
+		Message:           strings.TrimSpace(message),
+		ParseMode:         "HTML",
+		DisableWebPreview: true,
 	}
 }
 
diff --git a/services/webhook/telegram_test.go b/services/webhook/telegram_test.go
index 27ab96cd0..2fe5161b2 100644
--- a/services/webhook/telegram_test.go
+++ b/services/webhook/telegram_test.go
@@ -18,6 +18,15 @@ import (
 
 func TestTelegramPayload(t *testing.T) {
 	tc := telegramConvertor{}
+
+	t.Run("Correct webhook params", func(t *testing.T) {
+		p := createTelegramPayload("testMsg ")
+
+		assert.Equal(t, "HTML", p.ParseMode)
+		assert.Equal(t, true, p.DisableWebPreview)
+		assert.Equal(t, "testMsg", p.Message)
+	})
+
 	t.Run("Create", func(t *testing.T) {
 		p := createTestPayload()
 
diff --git a/tailwind.config.js b/tailwind.config.js
index d783268bd..0754ab363 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -55,5 +55,41 @@ export default {
       current: 'currentcolor',
       transparent: 'transparent',
     },
+    borderRadius: {
+      'none': '0',
+      'sm': '2px',
+      'DEFAULT': 'var(--border-radius)', // 4px
+      'md': 'var(--border-radius-medium)', // 6px
+      'lg': '8px',
+      'xl': '12px',
+      '2xl': '16px',
+      '3xl': '24px',
+      'full': 'var(--border-radius-circle)', // 50%
+    },
+    fontWeight: {
+      light: 'var(--font-weight-light)',
+      normal: 'var(--font-weight-normal)',
+      medium: 'var(--font-weight-medium)',
+      semibold: 'var(--font-weight-semibold)',
+      bold: 'var(--font-weight-bold)',
+    },
+    fontSize: { // not using `rem` units because our root is currently 14px
+      'xs': '12px',
+      'sm': '14px',
+      'base': '16px',
+      'lg': '18px',
+      'xl': '20px',
+      '2xl': '24px',
+      '3xl': '30px',
+      '4xl': '36px',
+      '5xl': '48px',
+      '6xl': '60px',
+      '7xl': '72px',
+      '8xl': '96px',
+      '9xl': '128px',
+      ...Object.fromEntries(Array.from({length: 100}, (_, i) => {
+        return [`${i}`, `${i === 0 ? '0' : `${i}px`}`];
+      })),
+    },
   },
 };
diff --git a/templates/admin/auth/new.tmpl b/templates/admin/auth/new.tmpl
index d8935341f..255eac202 100644
--- a/templates/admin/auth/new.tmpl
+++ b/templates/admin/auth/new.tmpl
@@ -99,7 +99,7 @@
 				<li>GitHub</li>
 				<span>{{ctx.Locale.Tr "admin.auths.tip.github"}}</span>
 				<li>GitLab</li>
-				<span>{{ctx.Locale.Tr "admin.auths.tip.gitlab"}}</span>
+				<span>{{ctx.Locale.Tr "admin.auths.tip.gitlab_new"}}</span>
 				<li>Google</li>
 				<span>{{ctx.Locale.Tr "admin.auths.tip.google_plus"}}</span>
 				<li>OpenID Connect</li>
diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl
index 1e552fba8..b72aef8f3 100644
--- a/templates/admin/emails/list.tmpl
+++ b/templates/admin/emails/list.tmpl
@@ -4,8 +4,8 @@
 			{{ctx.Locale.Tr "admin.emails.email_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})
 		</h4>
 		<div class="ui attached segment">
-			<div class="ui secondary filter menu gt-ac gt-mx-0">
-				<form class="ui form ignore-dirty gt-f1">
+			<div class="ui secondary filter menu tw-items-center gt-mx-0">
+				<form class="ui form ignore-dirty tw-flex-1">
 					{{template "shared/search/combo" dict "Value" .Keyword}}
 				</form>
 				<!-- Sort -->
@@ -15,10 +15,10 @@
 					</span>
 					{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 					<div class="menu">
-						<a class="{{if or (eq .SortType "email") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=email&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.email"}}</a>
-						<a class="{{if eq .SortType "reverseemail"}}active {{end}}item" href="{{$.Link}}?sort=reverseemail&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.email_reverse"}}</a>
-						<a class="{{if eq .SortType "username"}}active {{end}}item" href="{{$.Link}}?sort=username&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.name"}}</a>
-						<a class="{{if eq .SortType "reverseusername"}}active {{end}}item" href="{{$.Link}}?sort=reverseusername&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.name_reverse"}}</a>
+						<a class="{{if or (eq .SortType "email") (not .SortType)}}active {{end}}item" href="?sort=email&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.email"}}</a>
+						<a class="{{if eq .SortType "reverseemail"}}active {{end}}item" href="?sort=reverseemail&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.email_reverse"}}</a>
+						<a class="{{if eq .SortType "username"}}active {{end}}item" href="?sort=username&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.name"}}</a>
+						<a class="{{if eq .SortType "reverseusername"}}active {{end}}item" href="?sort=reverseusername&q={{$.Keyword}}">{{ctx.Locale.Tr "admin.emails.filter_sort.name_reverse"}}</a>
 					</div>
 				</div>
 			</div>
diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl
index e0abe4f8c..5ea003e5e 100644
--- a/templates/admin/notice.tmpl
+++ b/templates/admin/notice.tmpl
@@ -17,10 +17,10 @@
 			<tbody>
 				{{range .Notices}}
 					<tr>
-						<td><div class="ui checkbox gt-df" data-id="{{.ID}}"><input type="checkbox"></div></td>
+						<td><div class="ui checkbox tw-flex" data-id="{{.ID}}"><input type="checkbox"></div></td>
 						<td>{{.ID}}</td>
 						<td>{{ctx.Locale.Tr .TrStr}}</td>
-						<td class="view-detail auto-ellipsis" style="width: 80%;"><span class="notice-description">{{.Description}}</span></td>
+						<td class="view-detail auto-ellipsis tw-w-4/5"><span class="notice-description">{{.Description}}</span></td>
 						<td nowrap>{{DateTime "short" .CreatedUnix}}</td>
 						<td class="view-detail"><a href="#">{{svg "octicon-note" 16}}</a></td>
 					</tr>
@@ -49,8 +49,8 @@
 										</div>
 									</div>
 								</div>
-								<button class="ui small teal button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="{{.Link}}?page={{.Page.Paginater.Current}}">
-									{{ctx.Locale.Tr "admin.notices.delete_selected"}}
+								<button class="ui small teal button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="?page={{.Page.Paginater.Current}}">
+									<span class="text">{{ctx.Locale.Tr "admin.notices.delete_selected"}}</span>
 								</button>
 							</th>
 						</tr>
diff --git a/templates/admin/org/list.tmpl b/templates/admin/org/list.tmpl
index efb0a8847..ca0ee3009 100644
--- a/templates/admin/org/list.tmpl
+++ b/templates/admin/org/list.tmpl
@@ -7,8 +7,8 @@
 			</div>
 		</h4>
 		<div class="ui attached segment">
-			<div class="ui secondary filter menu gt-ac gt-mx-0">
-				<form class="ui form ignore-dirty gt-f1">
+			<div class="ui secondary filter menu tw-items-center gt-mx-0">
+				<form class="ui form ignore-dirty tw-flex-1">
 					{{template "shared/search/combo" dict "Value" .Keyword "Placeholder" (ctx.Locale.Tr "search.org_kind")}}
 				</form>
 				<!-- Sort -->
@@ -18,12 +18,12 @@
 					</span>
 					{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 					<div class="menu">
-						<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
-						<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
-						<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
-						<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
-						<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
-						<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
+						<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active {{end}}item" href="?sort=oldest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
+						<a class="{{if eq .SortType "newest"}}active {{end}}item" href="?sort=newest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
+						<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="?sort=alphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
+						<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="?sort=reversealphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
+						<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?sort=recentupdate&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
+						<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?sort=leastupdate&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
 					</div>
 				</div>
 			</div>
diff --git a/templates/admin/queue_manage.tmpl b/templates/admin/queue_manage.tmpl
index 80214d102..dd1682a00 100644
--- a/templates/admin/queue_manage.tmpl
+++ b/templates/admin/queue_manage.tmpl
@@ -30,7 +30,7 @@
 								-
 							{{else}}
 								{{$sum}}
-								<form action="{{$.Link}}/remove-all-items" method="post" class="gt-dib gt-ml-4">
+								<form action="{{$.Link}}/remove-all-items" method="post" class="tw-inline-block gt-ml-4">
 									{{$.CsrfTokenHtml}}
 									<button class="ui tiny basic red button">{{ctx.Locale.Tr "admin.monitor.queue.settings.remove_all_items"}}</button>
 								</form>
diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl
index c65cfd9db..9166a844a 100644
--- a/templates/admin/repo/unadopted.tmpl
+++ b/templates/admin/repo/unadopted.tmpl
@@ -20,8 +20,8 @@
 				{{if .Dirs}}
 					<div class="ui aligned divided list">
 						{{range $dirI, $dir := .Dirs}}
-							<div class="item gt-df gt-ac">
-								<span class="gt-f1"> {{svg "octicon-file-directory-fill"}} {{$dir}}</span>
+							<div class="item tw-flex tw-items-center">
+								<span class="tw-flex-1"> {{svg "octicon-file-directory-fill"}} {{$dir}}</span>
 								<div>
 									<button class="ui button primary show-modal gt-p-3" data-modal="#adopt-unadopted-modal-{{$dirI}}">{{svg "octicon-plus"}} {{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</button>
 									<div class="ui g-modal-confirm modal" id="adopt-unadopted-modal-{{$dirI}}">
diff --git a/templates/admin/stacktrace-row.tmpl b/templates/admin/stacktrace-row.tmpl
index ffb8bf812..3f639ba16 100644
--- a/templates/admin/stacktrace-row.tmpl
+++ b/templates/admin/stacktrace-row.tmpl
@@ -1,5 +1,5 @@
 <div class="item">
-	<div class="gt-df gt-ac">
+	<div class="tw-flex tw-items-center">
 		<div class="icon gt-ml-3 gt-mr-3">
 			{{if eq .Process.Type "request"}}
 				{{svg "octicon-globe" 16}}
@@ -11,7 +11,7 @@
 				{{svg "octicon-code" 16}}
 			{{end}}
 		</div>
-		<div class="content gt-f1">
+		<div class="content tw-flex-1">
 			<div class="header">{{.Process.Description}}</div>
 			<div class="description">{{if ne .Process.Type "none"}}{{TimeSince .Process.Start ctx.Locale}}{{end}}</div>
 		</div>
@@ -40,9 +40,9 @@
 						</summary>
 						<div class="list">
 							{{range .Entry}}
-								<div class="item gt-df gt-ac">
+								<div class="item tw-flex tw-items-center">
 									<span class="icon gt-mr-4">{{svg "octicon-dot-fill" 16}}</span>
-									<div class="content gt-f1">
+									<div class="content tw-flex-1">
 										<div class="header"><code>{{.Function}}</code></div>
 										<div class="description"><code>{{.File}}:{{.Line}}</code></div>
 									</div>
diff --git a/templates/admin/stacktrace.tmpl b/templates/admin/stacktrace.tmpl
index 42944615c..e324570c9 100644
--- a/templates/admin/stacktrace.tmpl
+++ b/templates/admin/stacktrace.tmpl
@@ -1,11 +1,11 @@
 {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin monitor")}}
 <div class="admin-setting-content">
 
-	<div class="gt-df gt-ac">
-		<div class="gt-f1">
+	<div class="tw-flex tw-items-center">
+		<div class="tw-flex-1">
 			<div class="ui compact small menu">
-				<a class="{{if eq .ShowGoroutineList "process"}}active {{end}}item" href="{{.Link}}?show=process">{{ctx.Locale.Tr "admin.monitor.process"}}</a>
-				<a class="{{if eq .ShowGoroutineList "stacktrace"}}active {{end}}item" href="{{.Link}}?show=stacktrace">{{ctx.Locale.Tr "admin.monitor.stacktrace"}}</a>
+				<a class="{{if eq .ShowGoroutineList "process"}}active {{end}}item" href="?show=process">{{ctx.Locale.Tr "admin.monitor.process"}}</a>
+				<a class="{{if eq .ShowGoroutineList "stacktrace"}}active {{end}}item" href="?show=stacktrace">{{ctx.Locale.Tr "admin.monitor.stacktrace"}}</a>
 			</div>
 		</div>
 		<form target="_blank" action="{{AppSubUrl}}/admin/monitor/diagnosis" class="ui form">
diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl
index 11c2fa594..e5d429952 100644
--- a/templates/admin/user/list.tmpl
+++ b/templates/admin/user/list.tmpl
@@ -103,7 +103,7 @@
 								<td><span>{{ctx.Locale.Tr "admin.users.never_login"}}</span></td>
 							{{end}}
 							<td>
-								<div class="gt-df gt-gap-3">
+								<div class="tw-flex tw-gap-2">
 									<a href="{{$.Link}}/{{.ID}}" data-tooltip-content="{{ctx.Locale.Tr "admin.users.details"}}">{{svg "octicon-person"}}</a>
 									<a href="{{$.Link}}/{{.ID}}/edit" data-tooltip-content="{{ctx.Locale.Tr "edit"}}">{{svg "octicon-pencil"}}</a>
 								</div>
diff --git a/templates/admin/user/view.tmpl b/templates/admin/user/view.tmpl
index fd3017607..21943a838 100644
--- a/templates/admin/user/view.tmpl
+++ b/templates/admin/user/view.tmpl
@@ -2,7 +2,7 @@
 
 <div class="admin-setting-content">
 	<div class="admin-responsive-columns">
-		<div class="gt-f1">
+		<div class="tw-flex-1">
 			<h4 class="ui top attached header">
 				{{.Title}}
 				<div class="ui right">
@@ -13,7 +13,7 @@
 				{{template "admin/user/view_details" .}}
 			</div>
 		</div>
-		<div class="gt-f1">
+		<div class="tw-flex-1">
 			<h4 class="ui top attached header">
 				{{ctx.Locale.Tr "admin.emails"}}
 				<div class="ui right">
diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl
index e75577598..ad80d3367 100644
--- a/templates/base/head_navbar.tmpl
+++ b/templates/base/head_navbar.tmpl
@@ -56,7 +56,7 @@
 	<div class="navbar-right ui secondary menu">
 		{{if and .IsSigned .MustChangePassword}}
 			<div class="ui dropdown jump item" data-tooltip-content="{{ctx.Locale.Tr "user_profile_and_more"}}">
-				<span class="text gt-df gt-ac">
+				<span class="text tw-flex tw-items-center">
 					{{ctx.AvatarUtils.Avatar .SignedUser 24 "gt-mr-2"}}
 					<span class="mobile-only gt-ml-3">{{.SignedUser.Name}}</span>
 					<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
@@ -83,8 +83,8 @@
 				<span class="mobile-only gt-ml-3">{{ctx.Locale.Tr "active_stopwatch"}}</span>
 			</a>
 			<div class="active-stopwatch-popup item tippy-target gt-p-3">
-				<div class="gt-df gt-ac">
-					<a class="stopwatch-link gt-df gt-ac" href="{{.ActiveStopwatch.IssueLink}}">
+				<div class="tw-flex tw-items-center">
+					<a class="stopwatch-link tw-flex tw-items-center" href="{{.ActiveStopwatch.IssueLink}}">
 						{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
 						<span class="stopwatch-issue">{{.ActiveStopwatch.RepoSlug}}#{{.ActiveStopwatch.IssueIndex}}</span>
 						<span class="ui primary label stopwatch-time gt-my-0 gt-mx-4" data-seconds="{{.ActiveStopwatch.Seconds}}">
@@ -142,7 +142,7 @@
 			</div><!-- end dropdown menu create new -->
 
 			<div class="ui dropdown jump item gt-mx-0 gt-pr-3" data-tooltip-content="{{ctx.Locale.Tr "user_profile_and_more"}}">
-				<span class="text gt-df gt-ac">
+				<span class="text tw-flex tw-items-center">
 					{{ctx.AvatarUtils.Avatar .SignedUser 24 "gt-mr-2"}}
 					<span class="mobile-only gt-ml-3">{{.SignedUser.Name}}</span>
 					<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
diff --git a/templates/base/paginate.tmpl b/templates/base/paginate.tmpl
index 8c2adc1f9..4455c20b3 100644
--- a/templates/base/paginate.tmpl
+++ b/templates/base/paginate.tmpl
@@ -17,7 +17,7 @@
 					{{if eq .Num -1}}
 						<a class="disabled item">...</a>
 					{{else}}
-						<a class="{{if .IsCurrent}}active {{end}}item tw-content-center" {{if not .IsCurrent}}href="{{$paginationLink}}?page={{.Num}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>{{.Num}}</a>
+						<a class="{{if .IsCurrent}}active {{end}}item tw-items-center" {{if not .IsCurrent}}href="{{$paginationLink}}?page={{.Num}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>{{.Num}}</a>
 					{{end}}
 				{{end}}
 				<a class="{{if not .HasNext}}disabled{{end}} item navigation" {{if .HasNext}}href="{{$paginationLink}}?page={{.Next}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>
diff --git a/templates/devtest/flex-list.tmpl b/templates/devtest/flex-list.tmpl
index c8584c110..fdb9eb6b3 100644
--- a/templates/devtest/flex-list.tmpl
+++ b/templates/devtest/flex-list.tmpl
@@ -73,7 +73,7 @@
 						</div>
 						<div class="flex-item-trailing">
 							<a class="muted" href="{{$.Link}}">
-								<span class="flex-text-inline"><i class="color-icon gt-mr-3" style="background-color: aqua"></i>Go</span>
+								<span class="flex-text-inline"><i class="color-icon gt-mr-3 tw-bg-blue"></i>Go</span>
 							</a>
 							<a class="text grey flex-text-inline" href="{{$.Link}}">{{svg "octicon-star" 16}}45000</a>
 							<a class="text grey flex-text-inline" href="{{$.Link}}">{{svg "octicon-git-branch" 16}}1234</a>
@@ -104,7 +104,7 @@
 		</div>
 
 		<h1>If parent provides the padding/margin space:</h1>
-		<div class="gt-border-secondary gt-py-4">
+		<div class="tw-border tw-border-secondary gt-py-4">
 			<div class="flex-list flex-space-fitted">
 				<div class="flex-item">item 1 (no padding top)</div>
 				<div class="flex-item">item 2 (no padding bottom)</div>
diff --git a/templates/devtest/fomantic-modal.tmpl b/templates/devtest/fomantic-modal.tmpl
index 0b4199a19..5cd36721a 100644
--- a/templates/devtest/fomantic-modal.tmpl
+++ b/templates/devtest/fomantic-modal.tmpl
@@ -73,7 +73,7 @@
 		{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" "I know and must do  this is dangerous operation")}}
 	</div>
 
-	<div class="modal-buttons flex-text-block gt-fw"></div>
+	<div class="modal-buttons flex-text-block tw-flex-wrap"></div>
 	<script type="module">
 		for (const el of $('.ui.modal')) {
 			const $btn = $('<button>').text(`${el.id}`).on('click', () => {
diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl
index 0b1f982ee..9ef0aa675 100644
--- a/templates/devtest/gitea-ui.tmpl
+++ b/templates/devtest/gitea-ui.tmpl
@@ -95,8 +95,8 @@
 
 	<div>
 		<h1>Loading</h1>
-		<div class="is-loading small-loading-icon gt-border-secondary gt-py-2"><span>loading ...</span></div>
-		<div class="is-loading gt-border-secondary gt-py-4">
+		<div class="is-loading small-loading-icon tw-border tw-border-secondary gt-py-2"><span>loading ...</span></div>
+		<div class="is-loading tw-border tw-border-secondary gt-py-4">
 			<p>loading ...</p>
 			<p>loading ...</p>
 			<p>loading ...</p>
diff --git a/templates/devtest/tmplerr.tmpl b/templates/devtest/tmplerr.tmpl
index 2fe3f1eff..dd938c895 100644
--- a/templates/devtest/tmplerr.tmpl
+++ b/templates/devtest/tmplerr.tmpl
@@ -1,10 +1,10 @@
 {{template "base/head" .}}
 <div class="page-content devtest">
-	<div class="gt-df">
-		<div style="width: 80%; ">
+	<div class="tw-flex">
+		<div class="tw-w-4/5">
 			hello hello hello hello hello hello hello hello hello hello
 		</div>
-		<div style="width: 20%;">
+		<div class="tw-w-1/5">
 			{{template "devtest/tmplerr-sub" .}}
 		</div>
 	</div>
diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl
index 2bda50671..505387988 100644
--- a/templates/explore/repo_list.tmpl
+++ b/templates/explore/repo_list.tmpl
@@ -32,7 +32,7 @@
 					</div>
 					<div class="flex-item-trailing">
 						{{if .PrimaryLanguage}}
-							<a class="muted" href="{{$.Link}}?q={{$.Keyword}}&sort={{$.SortType}}&language={{.PrimaryLanguage.Language}}{{if $.TabName}}&tab={{$.TabName}}{{end}}">
+							<a class="muted" href="?q={{$.Keyword}}&sort={{$.SortType}}&language={{.PrimaryLanguage.Language}}{{if $.TabName}}&tab={{$.TabName}}{{end}}">
 								<span class="flex-text-inline"><i class="color-icon gt-mr-3" style="background-color: {{.PrimaryLanguage.Color}}"></i>{{.PrimaryLanguage.Language}}</span>
 							</a>
 						{{end}}
diff --git a/templates/explore/search.tmpl b/templates/explore/search.tmpl
index 54d995989..c12ff325f 100644
--- a/templates/explore/search.tmpl
+++ b/templates/explore/search.tmpl
@@ -1,5 +1,5 @@
-<div class="ui small secondary filter menu gt-ac gt-mx-0">
-	<form class="ui form ignore-dirty gt-f1">
+<div class="ui small secondary filter menu tw-items-center gt-mx-0">
+	<form class="ui form ignore-dirty tw-flex-1">
 		{{if .PageIsExploreUsers}}
 			{{template "shared/search/combo" dict "Value" .Keyword "Placeholder" (ctx.Locale.Tr "search.user_kind")}}
 		{{else}}
@@ -13,10 +13,10 @@
 		</span>
 		{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 		<div class="menu">
-			<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
-			<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
-			<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
-			<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
+			<a class="{{if eq .SortType "newest"}}active {{end}}item" href="?sort=newest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
+			<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?sort=oldest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
+			<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="?sort=alphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
+			<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="?sort=reversealphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
 		</div>
 	</div>
 </div>
diff --git a/templates/explore/user_list.tmpl b/templates/explore/user_list.tmpl
index fb86fbbea..f2cf939ff 100644
--- a/templates/explore/user_list.tmpl
+++ b/templates/explore/user_list.tmpl
@@ -1,6 +1,6 @@
 <div class="flex-list">
 	{{range .Users}}
-		<div class="flex-item gt-ac">
+		<div class="flex-item tw-items-center">
 			<div class="flex-item-leading">
 				{{ctx.AvatarUtils.Avatar . 48}}
 			</div>
diff --git a/templates/org/header.tmpl b/templates/org/header.tmpl
index 943557b1c..6eb7feb33 100644
--- a/templates/org/header.tmpl
+++ b/templates/org/header.tmpl
@@ -1,13 +1,13 @@
-<div class="ui container gt-df">
+<div class="ui container tw-flex">
 	{{ctx.AvatarUtils.Avatar .Org 100 "org-avatar"}}
-	<div id="org-info" class="gt-df gt-fc">
+	<div id="org-info" class="tw-flex tw-flex-col">
 		<div class="ui header">
 			{{.Org.DisplayName}}
 			<span class="org-visibility">
 				{{if .Org.Visibility.IsLimited}}<span class="ui large basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.limited_shortname"}}</span>{{end}}
 				{{if .Org.Visibility.IsPrivate}}<span class="ui large basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.private_shortname"}}</span>{{end}}
 			</span>
-			<span class="gt-df gt-ac gt-gap-2 gt-ml-auto gt-font-16 tw-whitespace-nowrap">
+			<span class="tw-flex tw-items-center tw-gap-1 tw-ml-auto tw-text-16 tw-whitespace-nowrap">
 				{{if .EnableFeed}}
 					<a class="ui basic label button gt-mr-0" href="{{.Org.HomeLink}}.rss" data-tooltip-content="{{ctx.Locale.Tr "rss_feed"}}">
 						{{svg "octicon-rss" 24}}
diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl
index d0a39c04f..920a42a5d 100644
--- a/templates/org/home.tmpl
+++ b/templates/org/home.tmpl
@@ -30,9 +30,9 @@
 					<div class="divider"></div>
 				{{end}}
 				{{if .NumMembers}}
-					<h4 class="ui top attached header gt-df">
-						<strong class="gt-f1">{{ctx.Locale.Tr "org.members"}}</strong>
-						<a class="text grey gt-df gt-ac" href="{{.OrgLink}}/members"><span>{{.NumMembers}}</span> {{svg "octicon-chevron-right"}}</a>
+					<h4 class="ui top attached header tw-flex">
+						<strong class="tw-flex-1">{{ctx.Locale.Tr "org.members"}}</strong>
+						<a class="text grey tw-flex tw-items-center" href="{{.OrgLink}}/members"><span>{{.NumMembers}}</span> {{svg "octicon-chevron-right"}}</a>
 					</h4>
 					<div class="ui attached segment members">
 						{{$isMember := .IsOrganizationMember}}
@@ -44,9 +44,9 @@
 					</div>
 				{{end}}
 				{{if .IsOrganizationMember}}
-					<div class="ui top attached header gt-df">
-						<strong class="gt-f1">{{ctx.Locale.Tr "org.teams"}}</strong>
-						<a class="text grey gt-df gt-ac" href="{{.OrgLink}}/teams"><span>{{.Org.NumTeams}}</span> {{svg "octicon-chevron-right"}}</a>
+					<div class="ui top attached header tw-flex">
+						<strong class="tw-flex-1">{{ctx.Locale.Tr "org.teams"}}</strong>
+						<a class="text grey tw-flex tw-items-center" href="{{.OrgLink}}/teams"><span>{{.Org.NumTeams}}</span> {{svg "octicon-chevron-right"}}</a>
 					</div>
 					<div class="ui attached table segment teams">
 						{{range .Teams}}
diff --git a/templates/org/member/members.tmpl b/templates/org/member/members.tmpl
index 54f84450e..4388dc952 100644
--- a/templates/org/member/members.tmpl
+++ b/templates/org/member/members.tmpl
@@ -7,7 +7,7 @@
 		<div class="flex-list">
 			{{range .Members}}
 				{{$isPublic := index $.MembersIsPublicMember .ID}}
-				<div class="flex-item {{if $.PublicOnly}}gt-ac{{end}}">
+				<div class="flex-item {{if $.PublicOnly}}tw-items-center{{end}}">
 					<div class="flex-item-leading">
 						<a href="{{.HomeLink}}">{{ctx.AvatarUtils.Avatar . 48}}</a>
 					</div>
diff --git a/templates/org/settings/blocked_users.tmpl b/templates/org/settings/blocked_users.tmpl
index 7608ebb43..f685a1b99 100644
--- a/templates/org/settings/blocked_users.tmpl
+++ b/templates/org/settings/blocked_users.tmpl
@@ -1,7 +1,7 @@
 {{template "org/settings/layout_head" (dict "ctxData" . "pageClass" "organization settings blocked-users")}}
 <div class="org-setting-content">
 	<div class="ui attached segment">
-		<form class="ui form ignore-dirty gt-df gt-fw gt-gap-3" action="{{$.Link}}/block" method="post">
+		<form class="ui form ignore-dirty tw-flex tw-flex-wrap tw-gap-2" action="{{$.Link}}/block" method="post">
 			{{.CsrfTokenHtml}}
 			<input type="hidden" name="uid" value="">
 			<div class="ui left">
diff --git a/templates/org/settings/labels.tmpl b/templates/org/settings/labels.tmpl
index 8eb7b4584..25a562c97 100644
--- a/templates/org/settings/labels.tmpl
+++ b/templates/org/settings/labels.tmpl
@@ -1,7 +1,7 @@
 {{template "org/settings/layout_head" (dict "ctxData" . "pageClass" "organization settings labels")}}
 				<div class="org-setting-content">
-					<div class="gt-df gt-ac">
-						<div class="gt-f1">
+					<div class="tw-flex tw-items-center">
+						<div class="tw-flex-1">
 							{{ctx.Locale.Tr "org.settings.labels_desc"}}
 						</div>
 						<button class="ui small primary new-label button">{{ctx.Locale.Tr "repo.issues.new_label"}}</button>
diff --git a/templates/org/team/members.tmpl b/templates/org/team/members.tmpl
index 02220a917..aa358841d 100644
--- a/templates/org/team/members.tmpl
+++ b/templates/org/team/members.tmpl
@@ -9,7 +9,7 @@
 				{{template "org/team/navbar" .}}
 				{{if .IsOrganizationOwner}}
 					<div class="ui attached segment">
-						<form class="ui form ignore-dirty gt-df gt-fw gt-gap-3" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post">
+						<form class="ui form ignore-dirty tw-flex tw-flex-wrap tw-gap-2" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post">
 							{{.CsrfTokenHtml}}
 							<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
 							<div id="search-user-box" class="ui search gt-mr-3"{{if .IsEmailInviteEnabled}} data-allow-email="true" data-allow-email-description="{{ctx.Locale.Tr "org.teams.invite_team_member" $.Team.Name}}"{{end}}>
@@ -24,7 +24,7 @@
 				<div class="ui attached segment">
 					<div class="flex-list">
 						{{range .Team.Members}}
-							<div class="flex-item gt-ac">
+							<div class="flex-item tw-items-center">
 								<div class="flex-item-leading">
 									<a href="{{.HomeLink}}">{{ctx.AvatarUtils.Avatar . 32}}</a>
 								</div>
@@ -56,7 +56,7 @@
 				<div class="ui attached segment">
 					<div class="flex-list">
 						{{range .Invites}}
-							<div class="flex-item gt-ac">
+							<div class="flex-item tw-items-center">
 								<div class="flex-item-main">
 									{{.Email}}
 								</div>
diff --git a/templates/org/team/new.tmpl b/templates/org/team/new.tmpl
index 50ef53b91..d1e0dbe38 100644
--- a/templates/org/team/new.tmpl
+++ b/templates/org/team/new.tmpl
@@ -78,11 +78,11 @@
 										<tr>
 											<th>{{ctx.Locale.Tr "units.unit"}}</th>
 											<th class="center aligned">{{ctx.Locale.Tr "org.teams.none_access"}}
-											<span class="gt-vm" data-tooltip-content="{{ctx.Locale.Tr "org.teams.none_access_helper"}}">{{svg "octicon-question" 16 "gt-ml-2"}}</span></th>
+											<span class="tw-align-middle" data-tooltip-content="{{ctx.Locale.Tr "org.teams.none_access_helper"}}">{{svg "octicon-question" 16 "gt-ml-2"}}</span></th>
 											<th class="center aligned">{{ctx.Locale.Tr "org.teams.read_access"}}
-											<span class="gt-vm" data-tooltip-content="{{ctx.Locale.Tr "org.teams.read_access_helper"}}">{{svg "octicon-question" 16 "gt-ml-2"}}</span></th>
+											<span class="tw-align-middle" data-tooltip-content="{{ctx.Locale.Tr "org.teams.read_access_helper"}}">{{svg "octicon-question" 16 "gt-ml-2"}}</span></th>
 											<th class="center aligned">{{ctx.Locale.Tr "org.teams.write_access"}}
-											<span class="gt-vm" data-tooltip-content="{{ctx.Locale.Tr "org.teams.write_access_helper"}}">{{svg "octicon-question" 16 "gt-ml-2"}}</span></th>
+											<span class="tw-align-middle" data-tooltip-content="{{ctx.Locale.Tr "org.teams.write_access_helper"}}">{{svg "octicon-question" 16 "gt-ml-2"}}</span></th>
 										</tr>
 									</thead>
 									<tbody>
diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl
index bd38cda6d..202279240 100644
--- a/templates/org/team/repositories.tmpl
+++ b/templates/org/team/repositories.tmpl
@@ -9,8 +9,8 @@
 				{{template "org/team/navbar" .}}
 				{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}}
 				{{if $canAddRemove}}
-					<div class="ui attached segment gt-df gt-fw gt-gap-3">
-						<form class="ui form ignore-dirty gt-f1 gt-df" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post">
+					<div class="ui attached segment tw-flex tw-flex-wrap tw-gap-2">
+						<form class="ui form ignore-dirty tw-flex-1 tw-flex" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post">
 							{{.CsrfTokenHtml}}
 							<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search">
 								<div class="ui input">
@@ -19,7 +19,7 @@
 							</div>
 							<button class="ui primary button gt-ml-3">{{ctx.Locale.Tr "add"}}</button>
 						</form>
-						<div class="gt-dib">
+						<div class="tw-inline-block">
 							<button class="ui primary button link-action" data-modal-confirm="{{ctx.Locale.Tr "org.teams.add_all_repos_desc"}}" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/addall">{{ctx.Locale.Tr "add_all"}}</button>
 							<button class="ui red button link-action" data-modal-confirm="{{ctx.Locale.Tr "org.teams.remove_all_repos_desc"}}" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/removeall">{{ctx.Locale.Tr "remove_all"}}</button>
 						</div>
@@ -28,7 +28,7 @@
 				<div class="ui attached segment">
 					<div class="flex-list">
 						{{range .Team.Repos}}
-							<div class="flex-item gt-ac">
+							<div class="flex-item tw-items-center">
 								<div class="flex-item-leading">
 									{{template "repo/icon" .}}
 								</div>
diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl
index 54af71126..e81a71489 100644
--- a/templates/package/view.tmpl
+++ b/templates/package/view.tmpl
@@ -90,8 +90,8 @@
 				<a class="tw-float-right" href="{{$.PackageDescriptor.PackageWebLink}}/versions">{{ctx.Locale.Tr "packages.versions.view_all"}}</a>
 				<div class="ui relaxed list">
 				{{range .LatestVersions}}
-					<div class="item gt-df">
-						<a class="gt-f1 gt-ellipsis" title="{{.Version}}" href="{{$.PackageDescriptor.PackageWebLink}}/{{PathEscape .LowerVersion}}">{{.Version}}</a>
+					<div class="item tw-flex">
+						<a class="tw-flex-1 gt-ellipsis" title="{{.Version}}" href="{{$.PackageDescriptor.PackageWebLink}}/{{PathEscape .LowerVersion}}">{{.Version}}</a>
 						<span class="text small">{{DateTime "short" .CreatedUnix}}</span>
 					</div>
 				{{end}}
diff --git a/templates/projects/list.tmpl b/templates/projects/list.tmpl
index 414c9dca2..f33f9180b 100644
--- a/templates/projects/list.tmpl
+++ b/templates/projects/list.tmpl
@@ -1,11 +1,11 @@
 {{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
-	<div class="gt-df gt-sb gt-mb-4">
+	<div class="tw-flex tw-justify-between gt-mb-4">
 		<div class="small-menu-items ui compact tiny menu list-header-toggle">
-			<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{$.Link}}?state=open&q={{$.Keyword}}">
+			<a class="item{{if not .IsShowClosed}} active{{end}}" href="?state=open&q={{$.Keyword}}">
 				{{svg "octicon-project-symlink" 16 "gt-mr-3"}}
 				{{ctx.Locale.PrettyNumber .OpenCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.open_title"}}
 			</a>
-			<a class="item{{if .IsShowClosed}} active{{end}}" href="{{$.Link}}?state=closed&q={{$.Keyword}}">
+			<a class="item{{if .IsShowClosed}} active{{end}}" href="?state=closed&q={{$.Keyword}}">
 				{{svg "octicon-check" 16 "gt-mr-3"}}
 				{{ctx.Locale.PrettyNumber .ClosedCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.closed_title"}}
 			</a>
@@ -31,9 +31,9 @@
 		</span>
 		{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 		<div class="menu">
-			<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=oldest&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
-			<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=recentupdate&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
-			<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=leastupdate&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
+			<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?q={{$.Keyword}}&sort=oldest&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
+			<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?q={{$.Keyword}}&sort=recentupdate&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
+			<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?q={{$.Keyword}}&sort=leastupdate&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
 		</div>
 	</div>
 </div>
diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl
index a6e84024b..93c2cdbb5 100644
--- a/templates/projects/view.tmpl
+++ b/templates/projects/view.tmpl
@@ -1,7 +1,7 @@
 {{$canWriteProject := and .CanWriteProjects (or (not .Repository) (not .Repository.IsArchived))}}
 
 <div class="ui container">
-	<div class="gt-df gt-sb gt-ac gt-mb-4">
+	<div class="tw-flex tw-justify-between tw-items-center gt-mb-4">
 		<h2 class="gt-mb-0">{{.Project.Title}}</h2>
 		{{if $canWriteProject}}
 			<div class="ui compact mini menu">
diff --git a/templates/repo/actions/list.tmpl b/templates/repo/actions/list.tmpl
index 62d30305b..916949d4f 100644
--- a/templates/repo/actions/list.tmpl
+++ b/templates/repo/actions/list.tmpl
@@ -8,9 +8,9 @@
 		<div class="ui stackable grid">
 			<div class="four wide column">
 				<div class="ui fluid vertical menu">
-					<a class="item{{if not $.CurWorkflow}} active{{end}}" href="{{$.Link}}?actor={{$.CurActor}}&status={{$.CurStatus}}">{{ctx.Locale.Tr "actions.runs.all_workflows"}}</a>
+					<a class="item{{if not $.CurWorkflow}} active{{end}}" href="?actor={{$.CurActor}}&status={{$.CurStatus}}">{{ctx.Locale.Tr "actions.runs.all_workflows"}}</a>
 					{{range .workflows}}
-						<a class="item{{if eq .Entry.Name $.CurWorkflow}} active{{end}}" href="{{$.Link}}?workflow={{.Entry.Name}}&actor={{$.CurActor}}&status={{$.CurStatus}}">{{.Entry.Name}}
+						<a class="item{{if eq .Entry.Name $.CurWorkflow}} active{{end}}" href="?workflow={{.Entry.Name}}&actor={{$.CurActor}}&status={{$.CurStatus}}">{{.Entry.Name}}
 							{{if .ErrMsg}}
 								<span data-tooltip-content="{{.ErrMsg}}">
 									{{svg "octicon-alert" 16 "text red"}}
@@ -25,7 +25,7 @@
 				</div>
 			</div>
 			<div class="twelve wide column content">
-				<div class="ui secondary filter menu gt-je gt-df gt-ac">
+				<div class="ui secondary filter menu tw-justify-end tw-flex tw-items-center">
 					<!-- Actor -->
 					<div class="ui{{if not .Actors}} disabled{{end}} dropdown jump item">
 						<span class="text">{{ctx.Locale.Tr "actions.runs.actor"}}</span>
@@ -35,11 +35,11 @@
 								<i class="icon">{{svg "octicon-search"}}</i>
 								<input type="text" placeholder="{{ctx.Locale.Tr "actions.runs.actor"}}">
 							</div>
-							<a class="item{{if not $.CurActor}} active{{end}}" href="{{$.Link}}?workflow={{$.CurWorkflow}}&status={{$.CurStatus}}&actor=0">
+							<a class="item{{if not $.CurActor}} active{{end}}" href="?workflow={{$.CurWorkflow}}&status={{$.CurStatus}}&actor=0">
 								{{ctx.Locale.Tr "actions.runs.actors_no_select"}}
 							</a>
 							{{range .Actors}}
-								<a class="item{{if eq .ID $.CurActor}} active{{end}}" href="{{$.Link}}?workflow={{$.CurWorkflow}}&actor={{.ID}}&status={{$.CurStatus}}">
+								<a class="item{{if eq .ID $.CurActor}} active{{end}}" href="?workflow={{$.CurWorkflow}}&actor={{.ID}}&status={{$.CurStatus}}">
 									{{ctx.AvatarUtils.Avatar . 20}} {{.GetDisplayName}}
 								</a>
 							{{end}}
@@ -54,11 +54,11 @@
 								<i class="icon">{{svg "octicon-search"}}</i>
 								<input type="text" placeholder="{{ctx.Locale.Tr "actions.runs.status"}}">
 							</div>
-							<a class="item{{if not $.CurStatus}} active{{end}}" href="{{$.Link}}?workflow={{$.CurWorkflow}}&actor={{$.CurActor}}&status=0">
+							<a class="item{{if not $.CurStatus}} active{{end}}" href="?workflow={{$.CurWorkflow}}&actor={{$.CurActor}}&status=0">
 								{{ctx.Locale.Tr "actions.runs.status_no_select"}}
 							</a>
 							{{range .StatusInfoList}}
-								<a class="item{{if eq .Status $.CurStatus}} active{{end}}" href="{{$.Link}}?workflow={{$.CurWorkflow}}&actor={{$.CurActor}}&status={{.Status}}">
+								<a class="item{{if eq .Status $.CurStatus}} active{{end}}" href="?workflow={{$.CurWorkflow}}&actor={{$.CurActor}}&status={{.Status}}">
 									{{.DisplayedStatus}}
 								</a>
 							{{end}}
diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl
index 580fb08a9..d393df653 100644
--- a/templates/repo/actions/runs_list.tmpl
+++ b/templates/repo/actions/runs_list.tmpl
@@ -6,7 +6,7 @@
 	</div>
 	{{end}}
 	{{range .Runs}}
-		<div class="flex-item gt-ac">
+		<div class="flex-item tw-items-center">
 			<div class="flex-item-leading">
 				{{template "repo/actions/status" (dict "status" .Status.String)}}
 			</div>
diff --git a/templates/repo/actions/status.tmpl b/templates/repo/actions/status.tmpl
index 501657014..a0e02cf8d 100644
--- a/templates/repo/actions/status.tmpl
+++ b/templates/repo/actions/status.tmpl
@@ -12,7 +12,7 @@
 {{- $className = .className -}}
 {{- end -}}
 
-<span class="gt-df gt-ac" data-tooltip-content="{{ctx.Locale.Tr (printf "actions.status.%s" .status)}}">
+<span class="tw-flex tw-items-center" data-tooltip-content="{{ctx.Locale.Tr (printf "actions.status.%s" .status)}}">
 {{if eq .status "success"}}
 	{{svg "octicon-check-circle-fill" $size (printf "text green %s" $className)}}
 {{else if eq .status "skipped"}}
diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl
index 6e0d0d1a5..67046b814 100644
--- a/templates/repo/blame.tmpl
+++ b/templates/repo/blame.tmpl
@@ -11,11 +11,11 @@
 	{{end}}
 {{end}}
 <div class="{{TabSizeClass .Editorconfig .FileName}} non-diff-file-content">
-	<h4 class="file-header ui top attached header gt-df gt-ac gt-sb gt-fw">
-		<div class="file-header-left gt-df gt-ac gt-py-3 gt-pr-4">
+	<h4 class="file-header ui top attached header tw-flex tw-items-center tw-justify-between tw-flex-wrap">
+		<div class="file-header-left tw-flex tw-items-center gt-py-3 gt-pr-4">
 			{{template "repo/file_info" .}}
 		</div>
-		<div class="file-header-right file-actions gt-df gt-ac gt-fw">
+		<div class="file-header-right file-actions tw-flex tw-items-center tw-flex-wrap">
 			<div class="ui buttons">
 				<a class="ui tiny button" href="{{$.RawFileLink}}">{{ctx.Locale.Tr "repo.file_raw"}}</a>
 				{{if not .IsViewCommit}}
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl
index 48c14cf34..7e061696e 100644
--- a/templates/repo/branch/list.tmpl
+++ b/templates/repo/branch/list.tmpl
@@ -25,7 +25,7 @@
 									<button class="btn interact-fg gt-px-2" data-clipboard-text="{{.DefaultBranchBranch.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
 									{{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}}
 								</div>
-								<p class="info gt-df gt-ac gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{.RepoLink}}/commit/{{PathEscape .DefaultBranchBranch.DBBranch.CommitID}}">{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage (.Repository.ComposeMetas ctx)}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{TimeSince .DefaultBranchBranch.DBBranch.CommitTime.AsTime ctx.Locale}}{{if .DefaultBranchBranch.DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}</p>
+								<p class="info tw-flex tw-items-center gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{.RepoLink}}/commit/{{PathEscape .DefaultBranchBranch.DBBranch.CommitID}}">{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage (.Repository.ComposeMetas ctx)}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{TimeSince .DefaultBranchBranch.DBBranch.CommitTime.AsTime ctx.Locale}}{{if .DefaultBranchBranch.DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}</p>
 							</td>
 							<td class="right aligned middle aligned overflow-visible">
 								{{if and $.IsWriter (not $.Repository.IsArchived) (not .IsDeleted)}}
@@ -67,8 +67,8 @@
 			</div>
 		{{end}}
 
-		<h4 class="ui top attached header gt-df gt-ac gt-sb">
-			<div class="gt-df gt-ac">
+		<h4 class="ui top attached header tw-flex tw-items-center tw-justify-between">
+			<div class="tw-flex tw-items-center">
 				{{ctx.Locale.Tr "repo.branches"}}
 			</div>
 		</h4>
@@ -98,7 +98,7 @@
 									<button class="btn interact-fg gt-px-2" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
 									{{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DBBranch.CommitID)}}
 								</div>
-								<p class="info gt-df gt-ac gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .DBBranch.CommitID}}">{{ShortSha .DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DBBranch.CommitMessage ($.Repository.ComposeMetas ctx)}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{TimeSince .DBBranch.CommitTime.AsTime ctx.Locale}}{{if .DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} &nbsp;{{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}</p>
+								<p class="info tw-flex tw-items-center gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .DBBranch.CommitID}}">{{ShortSha .DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DBBranch.CommitMessage ($.Repository.ComposeMetas ctx)}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{TimeSince .DBBranch.CommitTime.AsTime ctx.Locale}}{{if .DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} &nbsp;{{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}</p>
 							{{end}}
 							</td>
 							<td class="two wide ui">
@@ -134,7 +134,7 @@
 									</a>
 									{{end}}
 								{{else}}
-									<a href="{{.LatestPullRequest.Issue.Link}}" class="gt-vm ref-issue">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
+									<a href="{{.LatestPullRequest.Issue.Link}}" class="tw-align-middle ref-issue">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
 									{{if .LatestPullRequest.HasMerged}}
 										<a href="{{.LatestPullRequest.Issue.Link}}" class="ui purple large label">{{svg "octicon-git-merge" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.pulls.merged"}}</a>
 									{{else if .LatestPullRequest.Issue.IsClosed}}
diff --git a/templates/repo/branch_dropdown.tmpl b/templates/repo/branch_dropdown.tmpl
index 8a5cdc7cc..e389a3c75 100644
--- a/templates/repo/branch_dropdown.tmpl
+++ b/templates/repo/branch_dropdown.tmpl
@@ -70,8 +70,8 @@
 <div class="js-branch-tag-selector {{if .ContainerClasses}}{{.ContainerClasses}}{{end}}">
 	{{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}}
 	<div class="ui dropdown custom">
-		<button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df gt-m-0">
-			<span class="text gt-df gt-ac gt-mr-2">
+		<button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex gt-m-0">
+			<span class="text tw-flex tw-items-center gt-mr-2">
 				{{if .release}}
 					{{ctx.Locale.Tr "repo.release.compare"}}
 				{{else}}
diff --git a/templates/repo/clone_buttons.tmpl b/templates/repo/clone_buttons.tmpl
index a664c4bda..89daba9dc 100644
--- a/templates/repo/clone_buttons.tmpl
+++ b/templates/repo/clone_buttons.tmpl
@@ -1,15 +1,15 @@
 <!-- there is always at least one button (by context/repo.go) -->
 {{if $.CloneButtonShowHTTPS}}
-	<button class="ui small compact clone button" id="repo-clone-https" data-link="{{$.CloneButtonOriginLink.HTTPS}}">
+	<button class="ui small button" id="repo-clone-https" data-link="{{$.CloneButtonOriginLink.HTTPS}}">
 		HTTPS
 	</button>
 {{end}}
 {{if $.CloneButtonShowSSH}}
-	<button class="ui small compact clone button" id="repo-clone-ssh" data-link="{{$.CloneButtonOriginLink.SSH}}">
+	<button class="ui small button" id="repo-clone-ssh" data-link="{{$.CloneButtonOriginLink.SSH}}">
 		SSH
 	</button>
 {{end}}
 <input id="repo-clone-url" size="20" class="js-clone-url" value="{{$.CloneButtonOriginLink.HTTPS}}" readonly>
-<button class="ui basic small compact icon button" id="clipboard-btn" data-tooltip-content="{{ctx.Locale.Tr "copy_url"}}" data-clipboard-target="#repo-clone-url" aria-label="{{ctx.Locale.Tr "copy_url"}}">
+<button class="ui small icon button" id="clipboard-btn" data-tooltip-content="{{ctx.Locale.Tr "copy_url"}}" data-clipboard-target="#repo-clone-url" aria-label="{{ctx.Locale.Tr "copy_url"}}">
 	{{svg "octicon-copy" 14}}
 </button>
diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl
index eac9d0e24..8dd401d28 100644
--- a/templates/repo/code/recently_pushed_new_branches.tmpl
+++ b/templates/repo/code/recently_pushed_new_branches.tmpl
@@ -1,6 +1,6 @@
 {{range .RecentlyPushedNewBranches}}
-	<div class="ui positive message gt-df gt-ac">
-		<div class="gt-f1">
+	<div class="ui positive message tw-flex tw-items-center">
+		<div class="tw-flex-1">
 			{{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}}
 			{{$repo := .GetRepo $.Context}}
 			{{$name := .Name}}
diff --git a/templates/repo/commit_load_branches_and_tags.tmpl b/templates/repo/commit_load_branches_and_tags.tmpl
index 883230ac2..49f732384 100644
--- a/templates/repo/commit_load_branches_and_tags.tmpl
+++ b/templates/repo/commit_load_branches_and_tags.tmpl
@@ -7,13 +7,13 @@
 	<div class="branch-and-tag-detail gt-hidden">
 		<div class="divider"></div>
 		<div>{{ctx.Locale.Tr "repo.commit.contained_in"}}</div>
-		<div class="gt-df gt-mt-3">
+		<div class="tw-flex gt-mt-3">
 			<div class="gt-p-2">{{svg "octicon-git-branch"}}</div>
-			<div class="branch-area flex-text-block gt-fw gt-f1"></div>
+			<div class="branch-area flex-text-block tw-flex-wrap tw-flex-1"></div>
 		</div>
-		<div class="gt-df gt-mt-3">
+		<div class="tw-flex gt-mt-3">
 			<div class="gt-p-2">{{svg "octicon-tag"}}</div>
-			<div class="tag-area flex-text-block gt-fw gt-f1"></div>
+			<div class="tag-area flex-text-block tw-flex-wrap tw-flex-1"></div>
 		</div>
 	</div>
 </div>
diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl
index 80af73ce4..345c28f47 100644
--- a/templates/repo/commit_page.tmpl
+++ b/templates/repo/commit_page.tmpl
@@ -18,8 +18,8 @@
 			{{end}}
 		{{end}}
 		<div class="ui top attached header clearing segment tw-relative commit-header {{$class}}">
-			<div class="gt-df gt-mb-4 gt-fw">
-				<h3 class="gt-mb-0 gt-f1"><span class="commit-summary" title="{{.Commit.Summary}}">{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3>
+			<div class="tw-flex gt-mb-4 tw-flex-wrap">
+				<h3 class="gt-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3>
 				{{if not $.PageIsWiki}}
 					<div>
 						<a class="ui primary tiny button" href="{{.SourcePath}}">
@@ -139,8 +139,8 @@
 			{{end}}
 			{{template "repo/commit_load_branches_and_tags" .}}
 		</div>
-		<div class="ui attached segment gt-df gt-ac gt-sb gt-py-2 commit-header-row gt-fw {{$class}}">
-				<div class="gt-df gt-ac author">
+		<div class="ui attached segment tw-flex tw-items-center tw-justify-between gt-py-2 commit-header-row tw-flex-wrap {{$class}}">
+				<div class="tw-flex tw-items-center author">
 					{{if .Author}}
 						{{ctx.AvatarUtils.Avatar .Author 28 "gt-mr-3"}}
 						{{if .Author.FullName}}
@@ -164,7 +164,7 @@
 						{{end}}
 					{{end}}
 				</div>
-				<div class="ui horizontal list gt-df gt-ac">
+				<div class="ui horizontal list tw-flex tw-items-center">
 					{{if .Parents}}
 						<div class="item">
 							<span>{{ctx.Locale.Tr "repo.diff.parent"}}</span>
@@ -184,8 +184,8 @@
 				</div>
 		</div>
 		{{if .Commit.Signature}}
-			<div class="ui bottom attached message tw-text-left gt-df gt-ac gt-sb commit-header-row gt-fw gt-mb-0 {{$class}}">
-				<div class="gt-df gt-ac">
+			<div class="ui bottom attached message tw-text-left tw-flex tw-items-center tw-justify-between commit-header-row tw-flex-wrap gt-mb-0 {{$class}}">
+				<div class="tw-flex tw-items-center">
 					{{if .Verification.Verified}}
 						{{if ne .Verification.SigningUser.ID 0}}
 							{{svg "gitea-lock" 16 "gt-mr-3"}}
@@ -209,7 +209,7 @@
 						<span class="ui text">{{ctx.Locale.Tr .Verification.Reason}}</span>
 					{{end}}
 				</div>
-				<div class="gt-df gt-ac">
+				<div class="tw-flex tw-items-center">
 					{{if .Verification.Verified}}
 						{{if ne .Verification.SigningUser.ID 0}}
 							{{svg "octicon-verified" 16 "gt-mr-3"}}
diff --git a/templates/repo/commit_statuses.tmpl b/templates/repo/commit_statuses.tmpl
index b035e74c2..f451ac06a 100644
--- a/templates/repo/commit_statuses.tmpl
+++ b/templates/repo/commit_statuses.tmpl
@@ -1,10 +1,10 @@
 {{if .Statuses}}
 	{{if and (eq (len .Statuses) 1) .Status.TargetURL}}
-		<a class="gt-vm {{.AdditionalClasses}} tw-no-underline" data-tippy="commit-statuses" href="{{.Status.TargetURL}}">
+		<a class="tw-align-middle {{.AdditionalClasses}} tw-no-underline" data-tippy="commit-statuses" href="{{.Status.TargetURL}}">
 			{{template "repo/commit_status" .Status}}
 		</a>
 	{{else}}
-		<span class="gt-vm {{.AdditionalClasses}}" data-tippy="commit-statuses" tabindex="0">
+		<span class="tw-align-middle {{.AdditionalClasses}}" data-tippy="commit-statuses" tabindex="0">
 			{{template "repo/commit_status" .Status}}
 		</span>
 	{{end}}
diff --git a/templates/repo/commits.tmpl b/templates/repo/commits.tmpl
index 7b3b27af1..1263bc9dd 100644
--- a/templates/repo/commits.tmpl
+++ b/templates/repo/commits.tmpl
@@ -4,7 +4,7 @@
 	<div class="ui container">
 		{{template "repo/sub_menu" .}}
 		<div class="repo-button-row">
-			<div class="gt-df gt-ac">
+			<div class="tw-flex tw-items-center">
 				{{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "gt-mr-2"}}
 				<a href="{{.RepoLink}}/graph" class="ui basic small compact button">
 					{{svg "octicon-git-branch"}}
diff --git a/templates/repo/commits_list_small.tmpl b/templates/repo/commits_list_small.tmpl
index 86e6b7225..b195f0648 100644
--- a/templates/repo/commits_list_small.tmpl
+++ b/templates/repo/commits_list_small.tmpl
@@ -13,7 +13,7 @@
 
 		{{$commitLink:= printf "%s/commit/%s" $.comment.Issue.PullRequest.BaseRepo.Link (PathEscape .ID.String)}}
 
-		<span class="shabox gt-df gt-ac tw-float-right">
+		<span class="shabox tw-flex tw-items-center tw-float-right">
 			{{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}}
 			{{$class := "ui sha label"}}
 			{{if .Signature}}
diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl
index 221ee8d99..48e9368c6 100644
--- a/templates/repo/commits_table.tmpl
+++ b/templates/repo/commits_table.tmpl
@@ -1,5 +1,5 @@
-<h4 class="ui top attached header commits-table gt-df gt-ac gt-sb">
-	<div class="commits-table-left gt-df gt-ac">
+<h4 class="ui top attached header commits-table tw-flex tw-items-center tw-justify-between">
+	<div class="commits-table-left tw-flex tw-items-center">
 		{{if or .PageIsCommits (gt .CommitCount 0)}}
 			{{.CommitCount}} {{ctx.Locale.Tr "repo.commits.commits"}}
 		{{else if .IsNothingToCompare}}
diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl
index 353f6db70..201bff805 100644
--- a/templates/repo/diff/blob_excerpt.tmpl
+++ b/templates/repo/diff/blob_excerpt.tmpl
@@ -3,7 +3,7 @@
 	<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}">
 		{{if eq .GetType 4}}
 			<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}">
-				<div class="gt-df">
+				<div class="tw-flex">
 				{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
 					<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}">
 						{{svg "octicon-fold-down"}}
@@ -49,7 +49,7 @@
 	<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}">
 		{{if eq .GetType 4}}
 			<td colspan="2" class="lines-num">
-				<div class="gt-df">
+				<div class="tw-flex">
 					{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
 						<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?data-query={{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}">
 							{{svg "octicon-fold-down"}}
diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl
index 886004ea6..672d1254d 100644
--- a/templates/repo/diff/box.tmpl
+++ b/templates/repo/diff/box.tmpl
@@ -1,7 +1,7 @@
 {{$showFileTree := (and (not .DiffNotAvailable) (gt .Diff.NumFiles 1))}}
 <div>
 	<div class="diff-detail-box diff-box">
-		<div class="gt-df gt-ac gt-fw gt-gap-3 gt-ml-1">
+		<div class="tw-flex tw-items-center tw-flex-wrap tw-gap-2 gt-ml-1">
 			{{if $showFileTree}}
 				<button class="diff-toggle-file-tree-button not-mobile btn interact-fg" data-show-text="{{ctx.Locale.Tr "repo.diff.show_file_tree"}}" data-hide-text="{{ctx.Locale.Tr "repo.diff.hide_file_tree"}}">
 					{{/* the icon meaning is reversed here, "octicon-sidebar-collapse" means show the file tree */}}
@@ -18,14 +18,14 @@
 				</script>
 			{{end}}
 			{{if not .DiffNotAvailable}}
-				<div class="diff-detail-stats gt-df gt-ac gt-fw">
+				<div class="diff-detail-stats tw-flex tw-items-center tw-flex-wrap">
 					{{svg "octicon-diff" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion}}
 				</div>
 			{{end}}
 		</div>
 		<div class="diff-detail-actions">
 			{{if and .PageIsPullFiles $.SignedUserID (not .IsArchived) (not .DiffNotAvailable)}}
-				<div class="not-mobile gt-df gt-ac gt-fc tw-whitespace-nowrap gt-mr-2">
+				<div class="not-mobile tw-flex tw-items-center tw-flex-col tw-whitespace-nowrap gt-mr-2">
 					<label for="viewed-files-summary" id="viewed-files-summary-label" data-text-changed-template="{{ctx.Locale.Tr "repo.pulls.viewed_files_label"}}">
 						{{ctx.Locale.Tr "repo.pulls.viewed_files_label" .Diff.NumViewedFiles .Diff.NumFiles}}
 					</label>
@@ -68,7 +68,7 @@
 				binaryFileMessage: "{{ctx.Locale.Tr "repo.diff.bin"}}",
 				showMoreMessage: "{{ctx.Locale.Tr "repo.diff.show_more"}}",
 				statisticsMessage: "{{ctx.Locale.Tr "repo.diff.stats_desc_file"}}",
-				linkLoadMore: "{{$.Link}}?skip-to={{.Diff.End}}&file-only=true",
+				linkLoadMore: "?skip-to={{.Diff.End}}&file-only=true",
 			};
 
 			// for first time loading, the diffFileInfo is a plain object
@@ -110,8 +110,8 @@
 					{{$isExpandable := or (gt $file.Addition 0) (gt $file.Deletion 0) $file.IsBin}}
 					{{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.IsArchived) $.IsShowingAllCommits}}
 					<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} gt-mt-0" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if or ($file.ShouldBeHidden) (not $isExpandable)}}data-folded="true"{{end}}>
-						<h4 class="diff-file-header sticky-2nd-row ui top attached normal header gt-df gt-ac gt-sb gt-fw">
-							<div class="diff-file-name gt-df gt-ac gt-gap-2 gt-fw">
+						<h4 class="diff-file-header sticky-2nd-row ui top attached normal header tw-flex tw-items-center tw-justify-between tw-flex-wrap">
+							<div class="diff-file-name tw-flex tw-items-center tw-gap-1 tw-flex-wrap">
 								<button class="fold-file btn interact-bg gt-p-2{{if not $isExpandable}} tw-invisible{{end}}">
 									{{if $file.ShouldBeHidden}}
 										{{svg "octicon-chevron-right" 18}}
@@ -119,7 +119,7 @@
 										{{svg "octicon-chevron-down" 18}}
 									{{end}}
 								</button>
-								<div class="gt-font-semibold gt-df gt-ac gt-mono">
+								<div class="tw-font-semibold tw-flex tw-items-center gt-mono">
 									{{if $file.IsBin}}
 										<span class="gt-ml-1 gt-mr-3">
 											{{ctx.Locale.Tr "repo.diff.bin"}}
@@ -144,7 +144,7 @@
 									<span class="gt-ml-4 gt-mono">{{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}}</span>
 								{{end}}
 							</div>
-							<div class="diff-file-header-actions gt-df gt-ac gt-gap-2 gt-fw">
+							<div class="diff-file-header-actions tw-flex tw-items-center tw-gap-1 tw-flex-wrap">
 								{{if $showFileViewToggle}}
 									<div class="ui compact icon buttons">
 										<button class="ui tiny basic button file-view-toggle" data-toggle-selector="#diff-source-{{$file.NameHash}}" data-tooltip-content="{{ctx.Locale.Tr "repo.file_view_source"}}">{{svg "octicon-code"}}</button>
@@ -181,13 +181,13 @@
 						<div class="diff-file-body ui attached unstackable table segment" {{if and $file.IsViewed $.IsShowingAllCommits}}data-folded="true"{{end}}>
 							<div id="diff-source-{{$file.NameHash}}" class="file-body file-code unicode-escaped code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} gt-hidden{{end}}">
 								{{if or $file.IsIncomplete $file.IsBin}}
-									<div class="diff-file-body binary" style="padding: 5px 10px;">
+									<div class="diff-file-body binary">
 										{{if $file.IsIncomplete}}
 											{{if $file.IsIncompleteLineTooLong}}
 												{{ctx.Locale.Tr "repo.diff.file_suppressed_line_too_long"}}
 											{{else}}
 												{{ctx.Locale.Tr "repo.diff.file_suppressed"}}
-												<a class="ui basic tiny button diff-load-button" data-href="{{$.Link}}?file-only=true&files={{$file.Name}}&files={{$file.OldName}}">{{ctx.Locale.Tr "repo.diff.load"}}</a>
+												<a class="ui basic tiny button diff-load-button" data-href="?file-only=true&files={{$file.Name}}&files={{$file.OldName}}">{{ctx.Locale.Tr "repo.diff.load"}}</a>
 											{{end}}
 										{{else}}
 											{{ctx.Locale.Tr "repo.diff.bin_not_shown"}}
@@ -221,9 +221,9 @@
 
 				{{if .Diff.IsIncomplete}}
 					<div class="diff-file-box diff-box file-content gt-mt-3" id="diff-incomplete">
-						<h4 class="ui top attached normal header gt-df gt-ac gt-sb">
+						<h4 class="ui top attached normal header tw-flex tw-items-center tw-justify-between">
 							{{ctx.Locale.Tr "repo.diff.too_many_files"}}
-							<a class="ui basic tiny button" id="diff-show-more-files" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{ctx.Locale.Tr "repo.diff.show_more"}}</a>
+							<a class="ui basic tiny button" id="diff-show-more-files" data-href="?skip-to={{.Diff.End}}&file-only=true">{{ctx.Locale.Tr "repo.diff.show_more"}}</a>
 						</h4>
 					</div>
 				{{end}}
diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl
index 465ed2b91..bcf91f74e 100644
--- a/templates/repo/diff/comments.tmpl
+++ b/templates/repo/diff/comments.tmpl
@@ -8,10 +8,10 @@
 		{{template "shared/user/avatarlink" dict "user" .Poster}}
 	{{end}}
 	<div class="content comment-container">
-		<div class="ui top attached header comment-header gt-df gt-ac gt-sb">
-			<div class="comment-header-left gt-df gt-ac">
+		<div class="ui top attached header comment-header tw-flex tw-items-center tw-justify-between">
+			<div class="comment-header-left tw-flex tw-items-center">
 				{{if .OriginalAuthor}}
-					<span class="text black gt-font-semibold gt-mr-2">
+					<span class="text black tw-font-semibold gt-mr-2">
 						{{svg (MigrationIcon $.root.Repository.GetOriginalURLHostname)}}
 						{{.OriginalAuthor}}
 					</span>
@@ -30,7 +30,7 @@
 					</span>
 				{{end}}
 			</div>
-			<div class="comment-header-right actions gt-df gt-ac">
+			<div class="comment-header-right actions tw-flex tw-items-center">
 				{{if .Invalidated}}
 					{{$referenceUrl := printf "%s#%s" $.root.Issue.Link .HashTag}}
 					<a href="{{AppSubUrl}}{{$referenceUrl}}" class="ui label basic small" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.review.outdated_description"}}">
diff --git a/templates/repo/diff/conversation.tmpl b/templates/repo/diff/conversation.tmpl
index feca7b6c0..8510f9410 100644
--- a/templates/repo/diff/conversation.tmpl
+++ b/templates/repo/diff/conversation.tmpl
@@ -5,8 +5,8 @@
 {{$referenceUrl := printf "%s#%s" $.Issue.Link (index .comments 0).HashTag}}
 <div class="conversation-holder" data-path="{{(index .comments 0).TreePath}}" data-side="{{if lt (index .comments 0).Line 0}}left{{else}}right{{end}}" data-idx="{{(index .comments 0).UnsignedLine}}">
 	{{if $resolved}}
-		<div class="ui attached header resolved-placeholder gt-df gt-ac gt-sb">
-			<div class="ui grey text gt-df gt-ac gt-fw gt-gap-2">
+		<div class="ui attached header resolved-placeholder tw-flex tw-items-center tw-justify-between">
+			<div class="ui grey text tw-flex tw-items-center tw-flex-wrap tw-gap-1">
 				{{svg "octicon-check" 16 "icon gt-mr-2"}}
 				<b>{{$resolveDoer.Name}}</b> {{ctx.Locale.Tr "repo.issues.review.resolved_by"}}
 				{{if $invalid}}
@@ -19,12 +19,12 @@
 					</a>
 				{{end}}
 			</div>
-			<div class="gt-df gt-ac gt-gap-3">
-				<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny labeled button show-outdated gt-df gt-ac">
+			<div class="tw-flex tw-items-center tw-gap-2">
+				<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny labeled button show-outdated tw-flex tw-items-center">
 					{{svg "octicon-unfold" 16 "gt-mr-3"}}
 					{{ctx.Locale.Tr "repo.issues.review.show_resolved"}}
 				</button>
-				<button id="hide-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny labeled button hide-outdated gt-df gt-ac gt-hidden">
+				<button id="hide-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny labeled button hide-outdated tw-flex tw-items-center gt-hidden">
 					{{svg "octicon-fold" 16 "gt-mr-3"}}
 					{{ctx.Locale.Tr "repo.issues.review.hide_resolved"}}
 				</button>
@@ -37,7 +37,7 @@
 				{{template "repo/diff/comments" dict "root" $ "comments" .comments}}
 			</ui>
 		</div>
-		<div class="gt-df gt-je gt-ac gt-fw gt-mt-3">
+		<div class="tw-flex tw-justify-end tw-items-center tw-flex-wrap gt-mt-3">
 			<div class="ui buttons gt-mr-2">
 				<button class="ui icon tiny basic button previous-conversation">
 					{{svg "octicon-arrow-up" 12 "icon"}} {{ctx.Locale.Tr "repo.issues.previous"}}
diff --git a/templates/repo/diff/new_review.tmpl b/templates/repo/diff/new_review.tmpl
index ae7182c93..9c824db0a 100644
--- a/templates/repo/diff/new_review.tmpl
+++ b/templates/repo/diff/new_review.tmpl
@@ -1,5 +1,5 @@
 <div id="review-box">
-	<button class="ui tiny primary button gt-pr-2 gt-df js-btn-review {{if not $.IsShowingAllCommits}}disabled{{end}}" {{if not $.IsShowingAllCommits}}data-tooltip-content="{{ctx.Locale.Tr "repo.pulls.review_only_possible_for_full_diff"}}"{{end}}>
+	<button class="ui tiny primary button gt-pr-2 tw-flex js-btn-review {{if not $.IsShowingAllCommits}}disabled{{end}}" {{if not $.IsShowingAllCommits}}data-tooltip-content="{{ctx.Locale.Tr "repo.pulls.review_only_possible_for_full_diff"}}"{{end}}>
 		{{ctx.Locale.Tr "repo.diff.review"}}
 		<span class="ui small label review-comments-counter" data-pending-comment-number="{{.PendingCodeCommentNumber}}">{{.PendingCodeCommentNumber}}</span>
 		{{svg "octicon-triangle-down" 14 "dropdown icon"}}
@@ -10,8 +10,8 @@
 			<form class="ui form form-fetch-action" action="{{.Link}}/reviews/submit" method="post">
 				{{.CsrfTokenHtml}}
 				<input type="hidden" name="commit_id" value="{{.AfterCommitID}}">
-				<div class="field gt-df gt-ac">
-					<div class="gt-f1">{{ctx.Locale.Tr "repo.diff.review.header"}}</div>
+				<div class="field tw-flex tw-items-center">
+					<div class="tw-flex-1">{{ctx.Locale.Tr "repo.diff.review.header"}}</div>
 					<a class="muted close">{{svg "octicon-x" 16}}</a>
 				</div>
 				<div class="field">
@@ -31,7 +31,7 @@
 				<div class="divider"></div>
 				{{$showSelfTooltip := (and $.IsSigned ($.Issue.IsPoster $.SignedUser.ID))}}
 				{{if $showSelfTooltip}}
-					<span class="gt-dib" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_approve"}}">
+					<span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_approve"}}">
 						<button type="submit" name="type" value="approve" disabled class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button>
 					</span>
 				{{else}}
@@ -39,7 +39,7 @@
 				{{end}}
 				<button type="submit" name="type" value="comment" class="ui submit tiny basic button btn-submit">{{ctx.Locale.Tr "repo.diff.review.comment"}}</button>
 				{{if $showSelfTooltip}}
-					<span class="gt-dib" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_reject"}}">
+					<span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_reject"}}">
 						<button type="submit" name="type" value="reject" disabled class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button>
 					</span>
 				{{else}}
diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl
index 00e23f5c1..0030bbef8 100644
--- a/templates/repo/diff/section_split.tmpl
+++ b/templates/repo/diff/section_split.tmpl
@@ -16,7 +16,7 @@
 			<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}" data-line-type="{{.GetHTMLDiffLineType}}">
 				{{if eq .GetType 4}}
 					<td class="lines-num lines-num-old">
-						<div class="gt-df">
+						<div class="tw-flex">
 						{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
 							<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
 								{{svg "octicon-fold-down"}}
diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl
index e3249c26d..112924d1a 100644
--- a/templates/repo/diff/section_unified.tmpl
+++ b/templates/repo/diff/section_unified.tmpl
@@ -12,7 +12,7 @@
 			{{if eq .GetType 4}}
 				{{if $.root.AfterCommitID}}
 					<td colspan="2" class="lines-num">
-						<div class="gt-df">
+						<div class="tw-flex">
 							{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
 								<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
 									{{svg "octicon-fold-down"}}
diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl
index a858a728e..d3665a9f8 100644
--- a/templates/repo/empty.tmpl
+++ b/templates/repo/empty.tmpl
@@ -37,7 +37,7 @@
 									</a>
 									{{end}}
 								{{end}}
-								<div class="ui action small input gt-df gt-f1">
+								<div class="clone-panel ui action small input tw-flex-1">
 									{{template "repo/clone_buttons" .}}
 								</div>
 							</div>
diff --git a/templates/repo/find/files.tmpl b/templates/repo/find/files.tmpl
index eac6ec201..eebdcb2b1 100644
--- a/templates/repo/find/files.tmpl
+++ b/templates/repo/find/files.tmpl
@@ -2,10 +2,10 @@
 <div role="main" aria-label="{{.Title}}" class="page-content repository">
 	{{template "repo/header" .}}
 	<div class="ui container">
-		<div class="gt-df gt-ac">
+		<div class="tw-flex tw-items-center">
 			<a href="{{$.RepoLink}}">{{.RepoName}}</a>
 			<span class="gt-mx-3">/</span>
-			<div class="ui input gt-f1">
+			<div class="ui input tw-flex-1">
 				<input id="repo-file-find-input" type="text" autofocus data-url-data-link="{{.DataLink}}" data-url-tree-link="{{.TreeLink}}">
 			</div>
 		</div>
diff --git a/templates/repo/forks.tmpl b/templates/repo/forks.tmpl
index b27b55c13..6acb89f36 100644
--- a/templates/repo/forks.tmpl
+++ b/templates/repo/forks.tmpl
@@ -6,7 +6,7 @@
 			{{ctx.Locale.Tr "repo.forks"}}
 		</h2>
 		{{range .Forks}}
-			<div class="gt-df gt-ac gt-py-3">
+			<div class="tw-flex tw-items-center gt-py-3">
 				<span class="gt-mr-2">{{ctx.AvatarUtils.Avatar .Owner}}</span>
 				<a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / <a href="{{.Link}}">{{.Name}}</a>
 			</div>
diff --git a/templates/repo/graph.tmpl b/templates/repo/graph.tmpl
index 37305d278..67804f117 100644
--- a/templates/repo/graph.tmpl
+++ b/templates/repo/graph.tmpl
@@ -50,7 +50,7 @@
 				</div>
 			</h2>
 			<div class="ui dividing"></div>
-			<div class="ui segment loading gt-hidden" id="loading-indicator"></div>
+			<div class="is-loading tw-py-32 gt-hidden" id="loading-indicator"></div>
 			{{template "repo/graph/svgcontainer" .}}
 			{{template "repo/graph/commits" .}}
 		</div>
diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl
index 61ef1fe10..b22527c8e 100644
--- a/templates/repo/graph/commits.tmpl
+++ b/templates/repo/graph/commits.tmpl
@@ -28,10 +28,10 @@
 							{{- end -}}
 						</a>
 					</span>
-					<span class="message gt-dib gt-ellipsis gt-mr-3">
+					<span class="message tw-inline-block gt-ellipsis gt-mr-3">
 						<span>{{RenderCommitMessage $.Context $commit.Subject ($.Repository.ComposeMetas ctx)}}</span>
 					</span>
-					<span class="commit-refs gt-df gt-ac gt-mr-2">
+					<span class="commit-refs tw-flex tw-items-center gt-mr-2">
 						{{range $commit.Refs}}
 							{{$refGroup := .RefGroup}}
 							{{if eq $refGroup "pull"}}
@@ -58,7 +58,7 @@
 							{{end}}
 						{{end}}
 					</span>
-					<span class="author gt-df gt-ac gt-mr-3">
+					<span class="author tw-flex tw-items-center gt-mr-3">
 						{{$userName := $commit.Commit.Author.Name}}
 						{{if $commit.User}}
 							{{if $commit.User.FullName}}
@@ -71,7 +71,7 @@
 							{{$userName}}
 						{{end}}
 					</span>
-					<span class="time gt-df gt-ac">{{DateTime "full" $commit.Date}}</span>
+					<span class="time tw-flex tw-items-center">{{DateTime "full" $commit.Date}}</span>
 				{{end}}
 			</li>
 		{{end}}
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl
index f59dd621b..53ce17dbc 100644
--- a/templates/repo/header.tmpl
+++ b/templates/repo/header.tmpl
@@ -2,11 +2,11 @@
 {{with .Repository}}
 	<div class="ui container">
 		<div class="repo-header">
-			<div class="flex-item gt-ac">
+			<div class="flex-item tw-items-center">
 				<div class="flex-item-leading">{{template "repo/icon" .}}</div>
 				<div class="flex-item-main">
-					<div class="flex-item-title gt-font-18">
-						<a class="muted gt-font-normal" href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a>/
+					<div class="flex-item-title tw-text-18">
+						<a class="muted tw-font-normal" href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a>/
 						<a class="muted" href="{{$.RepoLink}}">{{.Name}}</a></div>
 				</div>
 				<div class="flex-item-trailing">
diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl
index 6b4b22762..bfb5ab523 100644
--- a/templates/repo/home.tmpl
+++ b/templates/repo/home.tmpl
@@ -6,7 +6,7 @@
 		{{template "repo/code/recently_pushed_new_branches" .}}
 		{{if and (not .HideRepoInfo) (not .IsBlame)}}
 		<div class="ui repo-description gt-word-break">
-			<div id="repo-desc" class="gt-font-16">
+			<div id="repo-desc" class="tw-text-16">
 				{{$description := .Repository.DescriptionHTML $.Context}}
 				{{if $description}}<span class="description">{{$description | RenderCodeBlock}}</span>{{else if .IsRepositoryAdmin}}<span class="no-description text-italic">{{ctx.Locale.Tr "repo.no_desc"}}</span>{{end}}
 				<a class="link" href="{{.Repository.Website}}">{{.Repository.Website}}</a>
@@ -27,19 +27,19 @@
 				</form>
 			</div>
 		</div>
-		<div class="gt-df gt-ac gt-fw gt-gap-2" id="repo-topics">
+		<div class="tw-flex tw-items-center tw-flex-wrap tw-gap-1" id="repo-topics">
 			{{range .Topics}}<a class="ui repo-topic large label topic gt-m-0" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a>{{end}}
-			{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<button id="manage_topic" class="btn interact-fg gt-font-12">{{ctx.Locale.Tr "repo.topic.manage_topics"}}</button>{{end}}
+			{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<button id="manage_topic" class="btn interact-fg tw-text-12">{{ctx.Locale.Tr "repo.topic.manage_topics"}}</button>{{end}}
 		</div>
 		{{end}}
 		{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}
-		<div class="ui form gt-hidden gt-df gt-fc gt-mt-4" id="topic_edit">
-			<div class="field gt-f1 gt-mb-2">
-				<div class="ui fluid multiple search selection dropdown gt-fw" data-text-count-prompt="{{ctx.Locale.Tr "repo.topic.count_prompt"}}" data-text-format-prompt="{{ctx.Locale.Tr "repo.topic.format_prompt"}}">
+		<div class="ui form gt-hidden tw-flex tw-flex-col gt-mt-4" id="topic_edit">
+			<div class="field tw-flex-1 gt-mb-2">
+				<div class="ui fluid multiple search selection dropdown tw-flex-wrap" data-text-count-prompt="{{ctx.Locale.Tr "repo.topic.count_prompt"}}" data-text-format-prompt="{{ctx.Locale.Tr "repo.topic.format_prompt"}}">
 					<input type="hidden" name="topics" value="{{range $i, $v := .Topics}}{{.Name}}{{if Eval $i "+" 1 "<" (len $.Topics)}},{{end}}{{end}}">
 					{{range .Topics}}
 						{{/* keey the same layout as Fomantic UI generated labels */}}
-						<a class="ui label transition visible tw-cursor-default gt-dib" data-value="{{.Name}}">{{.Name}}{{svg "octicon-x" 16 "delete icon"}}</a>
+						<a class="ui label transition visible tw-cursor-default tw-inline-block" data-value="{{.Name}}">{{.Name}}{{svg "octicon-x" 16 "delete icon"}}</a>
 					{{end}}
 					<div class="text"></div>
 				</div>
@@ -69,7 +69,7 @@
 		{{end}}
 		{{template "repo/sub_menu" .}}
 		<div class="repo-button-row">
-			<div class="gt-df gt-ac gt-fw gt-gap-y-3">
+			<div class="tw-flex tw-items-center tw-flex-wrap tw-gap-y-2">
 				{{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "gt-mr-2"}}
 				{{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}}
 					{{$cmpBranch := ""}}
@@ -129,12 +129,12 @@
 					</span>
 				{{end}}
 			</div>
-			<div class="gt-df gt-ac">
+			<div class="tw-flex tw-items-center">
 				<!-- Only show clone panel in repository home page -->
 				{{if eq $n 0}}
-					<div class="ui action tiny input" id="clone-panel">
+					<div class="clone-panel ui action tiny input">
 						{{template "repo/clone_buttons" .}}
-						<button id="more-btn" class="ui basic small compact jump dropdown icon button" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}">
+						<button class="ui small jump dropdown icon button" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}">
 							{{svg "octicon-kebab-horizontal"}}
 							<div class="menu">
 								{{if not $.DisableDownloadSourceArchives}}
diff --git a/templates/repo/icon.tmpl b/templates/repo/icon.tmpl
index a001f8189..e5e0bd68e 100644
--- a/templates/repo/icon.tmpl
+++ b/templates/repo/icon.tmpl
@@ -1,6 +1,6 @@
 {{$avatarLink := (.RelAvatarLink ctx)}}
 {{if $avatarLink}}
-	<img class="ui avatar gt-vm" src="{{$avatarLink}}" width="24" height="24" alt="{{.FullName}}">
+	<img class="ui avatar tw-align-middle" src="{{$avatarLink}}" width="24" height="24" alt="{{.FullName}}">
 {{else if $.IsMirror}}
 	{{svg "octicon-mirror" 24}}
 {{else if $.IsFork}}
diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl
index ff635c736..3790e42b9 100644
--- a/templates/repo/issue/card.tmpl
+++ b/templates/repo/issue/card.tmpl
@@ -7,13 +7,13 @@
 		</div>
 	{{end}}
 	<div class="content gt-p-0 tw-w-full">
-		<div class="gt-df tw-items-start">
+		<div class="tw-flex tw-items-start">
 			<div class="issue-card-icon">
 				{{template "shared/issueicon" .}}
 			</div>
 			<a class="issue-card-title muted issue-title" href="{{.Link}}">{{.Title | RenderEmoji ctx | RenderCodeBlock}}</a>
 			{{if and $.isPinnedIssueCard $.Page.IsRepoAdmin}}
-				<a role="button" class="issue-card-unpin muted gt-df gt-ac" data-tooltip-content={{ctx.Locale.Tr "repo.issues.unpin_issue"}} data-issue-id="{{.ID}}" data-unpin-url="{{$.Page.Link}}/unpin/{{.Index}}">
+				<a role="button" class="issue-card-unpin muted tw-flex tw-items-center" data-tooltip-content={{ctx.Locale.Tr "repo.issues.unpin_issue"}} data-issue-id="{{.ID}}" data-unpin-url="{{$.Page.Link}}/unpin/{{.Index}}">
 					{{svg "octicon-x" 16}}
 				</a>
 			{{end}}
@@ -34,8 +34,8 @@
 		{{if .MilestoneID}}
 		<div class="meta gt-my-2">
 			<a class="milestone" href="{{.Repo.Link}}/milestone/{{.MilestoneID}}">
-				{{svg "octicon-milestone" 16 "gt-mr-2 gt-vm"}}
-				<span class="gt-vm">{{.Milestone.Name}}</span>
+				{{svg "octicon-milestone" 16 "gt-mr-2 tw-align-middle"}}
+				<span class="tw-align-middle">{{.Milestone.Name}}</span>
 			</a>
 		</div>
 		{{end}}
@@ -43,8 +43,8 @@
 		{{range index $.Page.LinkedPRs .ID}}
 		<div class="meta gt-my-2">
 			<a href="{{$.Issue.Repo.Link}}/pulls/{{.Index}}">
-				<span class="gt-m-0 text {{if .PullRequest.HasMerged}}purple{{else if .IsClosed}}red{{else}}green{{end}}">{{svg "octicon-git-merge" 16 "gt-mr-2 gt-vm"}}</span>
-				<span class="gt-vm">{{.Title}} <span class="text light grey">#{{.Index}}</span></span>
+				<span class="gt-m-0 text {{if .PullRequest.HasMerged}}purple{{else if .IsClosed}}red{{else}}green{{end}}">{{svg "octicon-git-merge" 16 "gt-mr-2 tw-align-middle"}}</span>
+				<span class="tw-align-middle">{{.Title}} <span class="text light grey">#{{.Index}}</span></span>
 			</a>
 		</div>
 		{{end}}
@@ -52,8 +52,8 @@
 		{{$tasks := .GetTasks}}
 		{{if gt $tasks 0}}
 			<div class="meta gt-my-2">
-				{{svg "octicon-checklist" 16 "gt-mr-2 gt-vm"}}
-				<span class="gt-vm">{{.GetTasksDone}} / {{$tasks}}</span>
+				{{svg "octicon-checklist" 16 "gt-mr-2 tw-align-middle"}}
+				<span class="tw-align-middle">{{.GetTasksDone}} / {{$tasks}}</span>
 			</div>
 		{{end}}
 	</div>
diff --git a/templates/repo/issue/filter_actions.tmpl b/templates/repo/issue/filter_actions.tmpl
index a2296f659..064b75af0 100644
--- a/templates/repo/issue/filter_actions.tmpl
+++ b/templates/repo/issue/filter_actions.tmpl
@@ -29,7 +29,7 @@
 						<div class="divider"></div>
 					{{end}}
 					{{$previousExclusiveScope = $exclusiveScope}}
-					<div class="item issue-action gt-df gt-sb" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels">
+					<div class="item issue-action tw-flex tw-justify-between" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels">
 						{{if SliceUtils.Contains $.SelLabelIDs .ID}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel $.Context .}}
 						{{template "repo/issue/labels/label_archived" .}}
 					</div>
diff --git a/templates/repo/issue/filter_list.tmpl b/templates/repo/issue/filter_list.tmpl
index f9f635f7c..cdb4b36bf 100644
--- a/templates/repo/issue/filter_list.tmpl
+++ b/templates/repo/issue/filter_list.tmpl
@@ -23,8 +23,8 @@
 		</div>
 		<span class="info">{{ctx.Locale.Tr "repo.issues.filter_label_exclude"}}</span>
 		<div class="divider"></div>
-		<a rel="nofollow" class="{{if .AllLabels}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_no_select"}}</a>
-		<a rel="nofollow" class="{{if .NoLabel}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels=0&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_select_no_label"}}</a>
+		<a rel="nofollow" class="{{if .AllLabels}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_no_select"}}</a>
+		<a rel="nofollow" class="{{if .NoLabel}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels=0&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_select_no_label"}}</a>
 		{{$previousExclusiveScope := "_no_scope"}}
 		{{range .Labels}}
 			{{$exclusiveScope := .ExclusiveScope}}
@@ -32,7 +32,7 @@
 				<div class="divider"></div>
 			{{end}}
 			{{$previousExclusiveScope = $exclusiveScope}}
-			<a rel="nofollow" class="item label-filter-item gt-df gt-ac" {{if .IsArchived}}data-is-archived{{end}} href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}" data-label-id="{{.ID}}">
+			<a rel="nofollow" class="item label-filter-item tw-flex tw-items-center" {{if .IsArchived}}data-is-archived{{end}} href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}" data-label-id="{{.ID}}">
 				{{if .IsExcluded}}
 					{{svg "octicon-circle-slash"}}
 				{{else if .IsSelected}}
@@ -43,7 +43,7 @@
 					{{end}}
 				{{end}}
 				{{RenderLabel $.Context .}}
-				<p class="gt-ml-auto">{{template "repo/issue/labels/label_archived" .}}</p>
+				<p class="tw-ml-auto">{{template "repo/issue/labels/label_archived" .}}</p>
 			</a>
 		{{end}}
 	</div>
@@ -62,13 +62,13 @@
 			<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_milestone"}}">
 		</div>
 		<div class="divider"></div>
-		<a rel="nofollow" class="{{if not $.MilestoneID}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=0&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_all"}}</a>
-		<a rel="nofollow" class="{{if $.MilestoneID}}{{if eq $.MilestoneID -1}}active selected {{end}}{{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=-1&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_none"}}</a>
+		<a rel="nofollow" class="{{if not $.MilestoneID}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=0&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_all"}}</a>
+		<a rel="nofollow" class="{{if $.MilestoneID}}{{if eq $.MilestoneID -1}}active selected {{end}}{{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=-1&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_none"}}</a>
 		{{if .OpenMilestones}}
 			<div class="divider"></div>
 			<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_open"}}</div>
 			{{range .OpenMilestones}}
-			<a rel="nofollow" class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
+			<a rel="nofollow" class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
 				{{svg "octicon-milestone" 16 "mr-2"}}
 				{{.Name}}
 			</a>
@@ -78,7 +78,7 @@
 			<div class="divider"></div>
 			<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_closed"}}</div>
 			{{range .ClosedMilestones}}
-			<a rel="nofollow" class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
+			<a rel="nofollow" class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
 				{{svg "octicon-milestone" 16 "mr-2"}}
 				{{.Name}}
 			</a>
@@ -99,16 +99,16 @@
 			<i class="icon">{{svg "octicon-search" 16}}</i>
 			<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_project"}}">
 		</div>
-		<a rel="nofollow" class="{{if not .ProjectID}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_project_all"}}</a>
-		<a rel="nofollow" class="{{if eq .ProjectID -1}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&project=-1&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_project_none"}}</a>
+		<a rel="nofollow" class="{{if not .ProjectID}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_project_all"}}</a>
+		<a rel="nofollow" class="{{if eq .ProjectID -1}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&project=-1&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_project_none"}}</a>
 		{{if .OpenProjects}}
 			<div class="divider"></div>
 			<div class="header">
 				{{ctx.Locale.Tr "repo.issues.new.open_projects"}}
 			</div>
 			{{range .OpenProjects}}
-				<a rel="nofollow" class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item gt-df" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
-					{{svg .IconName 18 "gt-mr-3 gt-shrink-0"}}<span class="gt-ellipsis">{{.Title}}</span>
+				<a rel="nofollow" class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item tw-flex" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
+					{{svg .IconName 18 "gt-mr-3 tw-shrink-0"}}<span class="gt-ellipsis">{{.Title}}</span>
 				</a>
 			{{end}}
 		{{end}}
@@ -118,7 +118,7 @@
 				{{ctx.Locale.Tr "repo.issues.new.closed_projects"}}
 			</div>
 			{{range .ClosedProjects}}
-				<a rel="nofollow" class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
+				<a rel="nofollow" class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
 					{{svg .IconName 18 "gt-mr-3"}}{{.Title}}
 				</a>
 			{{end}}
@@ -130,7 +130,7 @@
 <div class="ui dropdown jump item user-remote-search" data-tooltip-content="{{ctx.Locale.Tr "repo.author_search_tooltip"}}"
 	data-search-url="{{if .Milestone}}{{$.RepoLink}}/issues/posters{{else}}{{$.Link}}/posters{{end}}"
 	data-selected-user-id="{{$.PosterID}}"
-	data-action-jump-url="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={user_id}{{if $.ShowArchivedLabels}}&archived=true{{end}}"
+	data-action-jump-url="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={user_id}{{if $.ShowArchivedLabels}}&archived=true{{end}}"
 >
 	<span class="text">
 		{{ctx.Locale.Tr "repo.issues.filter_poster"}}
@@ -156,11 +156,11 @@
 			<i class="icon">{{svg "octicon-search" 16}}</i>
 			<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_assignee"}}">
 		</div>
-		<a rel="nofollow" class="{{if not .AssigneeID}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_select"}}</a>
-		<a rel="nofollow" class="{{if eq .AssigneeID -1}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee=-1&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee"}}</a>
+		<a rel="nofollow" class="{{if not .AssigneeID}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_select"}}</a>
+		<a rel="nofollow" class="{{if eq .AssigneeID -1}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee=-1&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee"}}</a>
 		<div class="divider"></div>
 		{{range .Assignees}}
-			<a rel="nofollow" class="{{if eq $.AssigneeID .ID}}active selected{{end}} item gt-df" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{.ID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
+			<a rel="nofollow" class="{{if eq $.AssigneeID .ID}}active selected{{end}} item tw-flex" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{.ID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
 				{{ctx.AvatarUtils.Avatar . 20}}{{template "repo/search_name" .}}
 			</a>
 		{{end}}
@@ -175,14 +175,14 @@
 		</span>
 		{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 		<div class="menu">
-			<a rel="nofollow" class="{{if eq .ViewType "all"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.all_issues"}}</a>
-			<a rel="nofollow" class="{{if eq .ViewType "assigned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
-			<a rel="nofollow" class="{{if eq .ViewType "created_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
+			<a rel="nofollow" class="{{if eq .ViewType "all"}}active {{end}}item" href="?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.all_issues"}}</a>
+			<a rel="nofollow" class="{{if eq .ViewType "assigned"}}active {{end}}item" href="?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
+			<a rel="nofollow" class="{{if eq .ViewType "created_by"}}active {{end}}item" href="?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
 			{{if .PageIsPullList}}
-				<a rel="nofollow" class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}}</a>
-				<a rel="nofollow" class="{{if eq .ViewType "reviewed_by"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=reviewed_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}}</a>
+				<a rel="nofollow" class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}}</a>
+				<a rel="nofollow" class="{{if eq .ViewType "reviewed_by"}}active {{end}}item" href="?q={{$.Keyword}}&type=reviewed_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}}</a>
 			{{end}}
-			<a rel="nofollow" class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
+			<a rel="nofollow" class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
 		</div>
 	</div>
 {{end}}
@@ -194,13 +194,13 @@
 	</span>
 	{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 	<div class="menu">
-		<a rel="nofollow" class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
-		<a rel="nofollow" class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
-		<a rel="nofollow" class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
-		<a rel="nofollow" class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
-		<a rel="nofollow" class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
-		<a rel="nofollow" class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
-		<a rel="nofollow" class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
-		<a rel="nofollow" class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort=farduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
+		<a rel="nofollow" class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
+		<a rel="nofollow" class="{{if eq .SortType "oldest"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
+		<a rel="nofollow" class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
+		<a rel="nofollow" class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
+		<a rel="nofollow" class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
+		<a rel="nofollow" class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
+		<a rel="nofollow" class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
+		<a rel="nofollow" class="{{if eq .SortType "farduedate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=farduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
 	</div>
 </div>
diff --git a/templates/repo/issue/label_precolors.tmpl b/templates/repo/issue/label_precolors.tmpl
index 146119b97..80007662c 100644
--- a/templates/repo/issue/label_precolors.tmpl
+++ b/templates/repo/issue/label_precolors.tmpl
@@ -1,5 +1,5 @@
 <div class="precolors">
-	<div class="gt-df">
+	<div class="tw-flex">
 		<a class="color" style="background-color:#e11d21" data-color-hex="#e11d21"></a>
 		<a class="color" style="background-color:#eb6420" data-color-hex="#eb6420"></a>
 		<a class="color" style="background-color:#fbca04" data-color-hex="#fbca04"></a>
@@ -9,7 +9,7 @@
 		<a class="color" style="background-color:#0052cc" data-color-hex="#0052cc"></a>
 		<a class="color" style="background-color:#5319e7" data-color-hex="#5319e7"></a>
 	</div>
-	<div class="gt-df">
+	<div class="tw-flex">
 		<a class="color" style="background-color:#f6c6c7" data-color-hex="#f6c6c7"></a>
 		<a class="color" style="background-color:#fad8c7" data-color-hex="#fad8c7"></a>
 		<a class="color" style="background-color:#fef2c0" data-color-hex="#fef2c0"></a>
diff --git a/templates/repo/issue/labels/label_list.tmpl b/templates/repo/issue/labels/label_list.tmpl
index 9b0061b60..cc244af17 100644
--- a/templates/repo/issue/labels/label_list.tmpl
+++ b/templates/repo/issue/labels/label_list.tmpl
@@ -9,10 +9,10 @@
 				</span>
 				{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 				<div class="left menu">
-					<a class="{{if or (eq .SortType "alphabetically") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
-					<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
-					<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="{{$.Link}}?sort=leastissues&state={{$.State}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
-					<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="{{$.Link}}?sort=mostissues&state={{$.State}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
+					<a class="{{if or (eq .SortType "alphabetically") (not .SortType)}}active {{end}}item" href="?sort=alphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
+					<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="?sort=reversealphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
+					<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="?sort=leastissues&state={{$.State}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
+					<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="?sort=mostissues&state={{$.State}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
 				</div>
 			</div>
 		</div>
@@ -42,9 +42,9 @@
 					<a class="open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
 				{{end}}
 			</div>
-			<div class="label-operation gt-df">
+			<div class="label-operation tw-flex">
 				{{template "repo/issue/labels/label_archived" .}}
-				<div class="gt-df gt-ml-auto">
+				<div class="tw-flex tw-ml-auto">
 					{{if and (not $.PageIsOrgSettingsLabels) (not $.Repository.IsArchived) (or $.CanWriteIssues $.CanWritePulls)}}
 						<a class="edit-label-button" href="#" data-id="{{.ID}}" data-title="{{.Name}}" {{if .Exclusive}}data-exclusive{{end}} {{if gt .ArchivedUnix 0}}data-is-archived{{end}} data-num-issues="{{.NumIssues}}" data-description="{{.Description}}" data-color={{.Color}}>{{svg "octicon-pencil"}} {{ctx.Locale.Tr "repo.issues.label_edit"}}</a>
 						<a class="delete-button" href="#" data-url="{{$.Link}}/delete" data-id="{{.ID}}">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.issues.label_delete"}}</a>
diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl
index 62c1d00f0..45bddefa4 100644
--- a/templates/repo/issue/list.tmpl
+++ b/templates/repo/issue/list.tmpl
@@ -2,6 +2,7 @@
 <div role="main" aria-label="{{.Title}}" class="page-content repository issue-list">
 	{{template "repo/header" .}}
 	<div class="ui container">
+	{{template "base/alert" .}}
 
 	{{if .PinnedIssues}}
 		<div id="issue-pins" {{if .IsRepoAdmin}}data-is-repo-admin{{end}}>
diff --git a/templates/repo/issue/milestone/filter_list.tmpl b/templates/repo/issue/milestone/filter_list.tmpl
index 0eea42d6e..45f9866a1 100644
--- a/templates/repo/issue/milestone/filter_list.tmpl
+++ b/templates/repo/issue/milestone/filter_list.tmpl
@@ -5,11 +5,11 @@
 	</span>
 	{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 	<div class="menu">
-		<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.earliest_due_data"}}</a>
-		<a class="{{if eq .SortType "furthestduedate"}}active {{end}}item" href="{{$.Link}}?sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.latest_due_date"}}</a>
-		<a class="{{if eq .SortType "leastcomplete"}}active {{end}}item" href="{{$.Link}}?sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
-		<a class="{{if eq .SortType "mostcomplete"}}active {{end}}item" href="{{$.Link}}?sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
-		<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="{{$.Link}}?sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
-		<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="{{$.Link}}?sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
+		<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active {{end}}item" href="?sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.earliest_due_data"}}</a>
+		<a class="{{if eq .SortType "furthestduedate"}}active {{end}}item" href="?sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.latest_due_date"}}</a>
+		<a class="{{if eq .SortType "leastcomplete"}}active {{end}}item" href="?sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
+		<a class="{{if eq .SortType "mostcomplete"}}active {{end}}item" href="?sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
+		<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="?sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
+		<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="?sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
 	</div>
 </div>
diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl
index 35a8a7768..8ba7eecf4 100644
--- a/templates/repo/issue/milestone_issues.tmpl
+++ b/templates/repo/issue/milestone_issues.tmpl
@@ -2,10 +2,11 @@
 <div role="main" aria-label="{{.Title}}" class="page-content repository milestone-issue-list">
 	{{template "repo/header" .}}
 	<div class="ui container">
-		<div class="gt-df">
+		{{template "base/alert" .}}
+		<div class="tw-flex">
 			<h1 class="gt-mb-3">{{.Milestone.Name}}</h1>
 			{{if not .Repository.IsArchived}}
-				<div class="text right gt-f1">
+				<div class="text right tw-flex-1">
 					{{if or .CanWriteIssues .CanWritePulls}}
 						{{if .Milestone.IsClosed}}
 							<a class="ui primary basic button link-action" href data-url="{{$.RepoLink}}/milestones/{{.MilestoneID}}/open">{{ctx.Locale.Tr "repo.milestones.open"}}
@@ -25,10 +26,10 @@
 				{{.Milestone.RenderedContent}}
 		</div>
 		{{end}}
-		<div class="gt-df gt-fc gt-gap-3">
+		<div class="tw-flex tw-flex-col tw-gap-2">
 			<progress class="milestone-progress-big" value="{{.Milestone.Completeness}}" max="100"></progress>
-			<div class="gt-df gt-gap-4">
-				<div classs="gt-df gt-ac">
+			<div class="tw-flex tw-gap-4">
+				<div classs="tw-flex tw-items-center">
 					{{$closedDate:= TimeSinceUnix .Milestone.ClosedDateUnix ctx.Locale}}
 					{{if .IsClosed}}
 						{{svg "octicon-clock"}} {{ctx.Locale.Tr "repo.milestones.closed" $closedDate}}
diff --git a/templates/repo/issue/milestones.tmpl b/templates/repo/issue/milestones.tmpl
index 363ba7e3a..57b697d8f 100644
--- a/templates/repo/issue/milestones.tmpl
+++ b/templates/repo/issue/milestones.tmpl
@@ -23,7 +23,7 @@
 							{{svg "octicon-milestone" 16}}
 							<a class="muted" href="{{$.RepoLink}}/milestone/{{.ID}}">{{.Name}}</a>
 						</h3>
-						<div class="gt-df gt-ac">
+						<div class="tw-flex tw-items-center">
 							<span class="gt-mr-3">{{.Completeness}}%</span>
 							<progress value="{{.Completeness}}" max="100"></progress>
 						</div>
diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl
index b2b9e308f..ba1e19bf0 100644
--- a/templates/repo/issue/new_form.tmpl
+++ b/templates/repo/issue/new_form.tmpl
@@ -171,7 +171,7 @@
 				<div class="selected">
 				{{range .Assignees}}
 					<a class="item gt-p-2 muted gt-hidden" id="assignee_{{.ID}}" href="{{$.RepoLink}}/issues?assignee={{.ID}}">
-						{{ctx.AvatarUtils.Avatar . 28 "gt-mr-3 gt-vm"}}{{.GetDisplayName}}
+						{{ctx.AvatarUtils.Avatar . 28 "gt-mr-3 tw-align-middle"}}{{.GetDisplayName}}
 					</a>
 				{{end}}
 				</div>
diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl
index 7e6816613..c885f2e93 100644
--- a/templates/repo/issue/view_content.tmpl
+++ b/templates/repo/issue/view_content.tmpl
@@ -20,10 +20,10 @@
 				</a>
 				{{end}}
 				<div class="content comment-container">
-					<div class="ui top attached header comment-header gt-df gt-ac gt-sb" role="heading" aria-level="3">
-						<div class="comment-header-left gt-df gt-ac">
+					<div class="ui top attached header comment-header tw-flex tw-items-center tw-justify-between" role="heading" aria-level="3">
+						<div class="comment-header-left tw-flex tw-items-center">
 							{{if .Issue.OriginalAuthor}}
-								<span class="text black gt-font-semibold">
+								<span class="text black tw-font-semibold">
 									{{svg (MigrationIcon .Repository.GetOriginalURLHostname)}}
 									{{.Issue.OriginalAuthor}}
 								</span>
@@ -43,7 +43,7 @@
 								</span>
 							{{end}}
 						</div>
-						<div class="comment-header-right actions gt-df gt-ac">
+						<div class="comment-header-right actions tw-flex tw-items-center">
 							{{template "repo/issue/view_content/show_role" dict "ShowRole" .Issue.ShowRole "IgnorePoster" true}}
 							{{if not $.Repository.IsArchived}}
 								{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}}
diff --git a/templates/repo/issue/view_content/attachments.tmpl b/templates/repo/issue/view_content/attachments.tmpl
index 2c3a47d67..0635a201b 100644
--- a/templates/repo/issue/view_content/attachments.tmpl
+++ b/templates/repo/issue/view_content/attachments.tmpl
@@ -4,8 +4,8 @@
 	{{end}}
 	{{$hasThumbnails := false}}
 	{{- range .Attachments -}}
-		<div class="gt-df">
-			<div class="gt-f1 gt-p-3">
+		<div class="tw-flex">
+			<div class="tw-flex-1 gt-p-3">
 				<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}" title="{{ctx.Locale.Tr "repo.issues.attachment.open_tab" .Name}}">
 					{{if FilenameIsImage .Name}}
 						{{if not (StringUtils.Contains (StringUtils.ToString $.RenderedContent) .UUID)}}
@@ -18,7 +18,7 @@
 					<span><strong>{{.Name}}</strong></span>
 				</a>
 			</div>
-			<div class="gt-p-3 gt-df gt-ac">
+			<div class="gt-p-3 tw-flex tw-items-center">
 				<span class="ui text grey">{{.Size | FileSize}}</span>
 			</div>
 		</div>
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl
index 6e585f028..2038eb7c4 100644
--- a/templates/repo/issue/view_content/comments.tmpl
+++ b/templates/repo/issue/view_content/comments.tmpl
@@ -25,10 +25,10 @@
 				</a>
 			{{end}}
 				<div class="content comment-container">
-					<div class="ui top attached header comment-header gt-df gt-ac gt-sb" role="heading" aria-level="3">
-						<div class="comment-header-left gt-df gt-ac">
+					<div class="ui top attached header comment-header tw-flex tw-items-center tw-justify-between" role="heading" aria-level="3">
+						<div class="comment-header-left tw-flex tw-items-center">
 							{{if .OriginalAuthor}}
-								<span class="text black gt-font-semibold gt-mr-2">
+								<span class="text black tw-font-semibold gt-mr-2">
 									{{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}}
 									{{.OriginalAuthor}}
 								</span>
@@ -50,7 +50,7 @@
 								</span>
 							{{end}}
 						</div>
-						<div class="comment-header-right actions gt-df gt-ac">
+						<div class="comment-header-right actions tw-flex tw-items-center">
 							{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}}
 							{{if not $.Repository.IsArchived}}
 								{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}}
@@ -376,10 +376,9 @@
 			<div class="timeline-item-group" id="{{.HashTag}}">
 				<div class="timeline-item event">
 					{{if not .OriginalAuthor}}
-					{{/* Some timeline avatars need a offset to correctly align with their speech
-							bubble. The condition depends on review type and for positive reviews whether
-							there is a comment element or not */}}
-					<a class="timeline-avatar{{if or (and (eq .Review.Type 1) (or .Content .Attachments)) (and (eq .Review.Type 2) (or .Content .Attachments)) (eq .Review.Type 3)}} timeline-avatar-offset{{end}}"{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}>
+					{{/* Some timeline avatars need a offset to correctly align with their speech bubble.
+						The condition depends on whether the comment has contents/attachments or reviews */}}
+					<a class="timeline-avatar{{if or .Content .Attachments (and .Review .Review.CodeComments)}} timeline-avatar-offset{{end}}"{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}>
 						{{ctx.AvatarUtils.Avatar .Poster 40}}
 					</a>
 					{{end}}
@@ -403,8 +402,8 @@
 				{{if or .Content .Attachments}}
 				<div class="timeline-item comment">
 					<div class="content comment-container">
-						<div class="ui top attached header comment-header gt-df gt-ac gt-sb">
-							<div class="comment-header-left gt-df gt-ac">
+						<div class="ui top attached header comment-header tw-flex tw-items-center tw-justify-between">
+							<div class="comment-header-left tw-flex tw-items-center">
 								{{if gt .Poster.ID 0}}
 									<a class="inline-timeline-avatar" href="{{.Poster.HomeLink}}">
 										{{ctx.AvatarUtils.Avatar .Poster 24}}
@@ -412,7 +411,7 @@
 								{{end}}
 								<span class="text grey muted-links">
 									{{if .OriginalAuthor}}
-										<span class="text black gt-font-semibold">
+										<span class="text black tw-font-semibold">
 											{{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}}
 											{{.OriginalAuthor}}
 										</span>
@@ -425,7 +424,7 @@
 									{{ctx.Locale.Tr "repo.issues.review.left_comment"}}
 								</span>
 							</div>
-							<div class="comment-header-right actions gt-df gt-ac">
+							<div class="comment-header-right actions tw-flex tw-items-center">
 								{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}}
 								{{if not $.Repository.IsArchived}}
 									{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}}
@@ -622,7 +621,7 @@
 				{{if .Content}}
 					<div class="timeline-item comment">
 						<div class="content">
-							<div class="ui top attached header comment-header-left gt-df gt-ac arrow-top">
+							<div class="ui top attached header comment-header-left tw-flex tw-items-center arrow-top">
 								{{if gt .Poster.ID 0}}
 									<a class="inline-timeline-avatar" href="{{.Poster.HomeLink}}">
 										{{ctx.AvatarUtils.Avatar .Poster 24}}
diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl
index b6e075d0c..f94aa290f 100644
--- a/templates/repo/issue/view_content/conversation.tmpl
+++ b/templates/repo/issue/view_content/conversation.tmpl
@@ -3,8 +3,8 @@
 {{$resolveDoer := (index .comments 0).ResolveDoer}}
 {{$isNotPending := (not (eq (index .comments 0).Review.Type 0))}}
 <div class="ui segments conversation-holder">
-	<div class="ui segment collapsible-comment-box gt-py-3 gt-df gt-ac gt-sb">
-		<div class="gt-df gt-ac">
+	<div class="ui segment collapsible-comment-box gt-py-3 tw-flex tw-items-center tw-justify-between">
+		<div class="tw-flex tw-items-center">
 			<a href="{{(index .comments 0).CodeCommentLink ctx}}" class="file-comment gt-ml-3 gt-word-break">{{(index .comments 0).TreePath}}</a>
 			{{if $invalid}}
 				<span class="ui label basic small gt-ml-3" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.review.outdated_description"}}">
@@ -14,7 +14,7 @@
 		</div>
 		<div>
 			{{if or $invalid $resolved}}
-				<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="{{if not $resolved}}gt-hidden {{end}}ui compact labeled button show-outdated gt-df gt-ac">
+				<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="{{if not $resolved}}gt-hidden {{end}}ui compact labeled button show-outdated tw-flex tw-items-center">
 					{{svg "octicon-unfold" 16 "gt-mr-3"}}
 					{{if $resolved}}
 						{{ctx.Locale.Tr "repo.issues.review.show_resolved"}}
@@ -22,7 +22,7 @@
 						{{ctx.Locale.Tr "repo.issues.review.show_outdated"}}
 					{{end}}
 				</button>
-				<button id="hide-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="{{if $resolved}}gt-hidden {{end}}ui compact labeled button hide-outdated gt-df gt-ac">
+				<button id="hide-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="{{if $resolved}}gt-hidden {{end}}ui compact labeled button hide-outdated tw-flex tw-items-center">
 					{{svg "octicon-fold" 16 "gt-mr-3"}}
 					{{if $resolved}}
 						{{ctx.Locale.Tr "repo.issues.review.hide_resolved"}}
@@ -55,7 +55,7 @@
 				<div class="comment code-comment gt-pb-4" id="{{.HashTag}}">
 					<div class="content">
 						<div class="header comment-header">
-							<div class="comment-header-left gt-df gt-ac">
+							<div class="comment-header-left tw-flex tw-items-center">
 								{{if not .OriginalAuthor}}
 									<a class="avatar">
 										{{ctx.AvatarUtils.Avatar .Poster 20}}
@@ -76,7 +76,7 @@
 									{{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdSubStr}}
 								</span>
 							</div>
-							<div class="comment-header-right actions gt-df gt-ac">
+							<div class="comment-header-right actions tw-flex tw-items-center">
 								{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}}
 								{{if not $.Repository.IsArchived}}
 									{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}}
@@ -106,8 +106,8 @@
 				</div>
 			{{end}}
 		</div>
-		<div class="code-comment-buttons gt-df gt-ac gt-fw gt-mt-3 gt-mb-2 gt-mx-3">
-			<div class="gt-f1">
+		<div class="code-comment-buttons tw-flex tw-items-center tw-flex-wrap gt-mt-3 gt-mb-2 gt-mx-3">
+			<div class="tw-flex-1">
 				{{if $resolved}}
 					<div class="ui grey text">
 						{{svg "octicon-check" 16 "gt-mr-2"}}
diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl
index 23257b5a6..19f1d3f91 100644
--- a/templates/repo/issue/view_content/pull.tmpl
+++ b/templates/repo/issue/view_content/pull.tmpl
@@ -33,7 +33,7 @@
 		<div class="ui attached merge-section segment {{if not $.LatestCommitStatus}}no-header{{end}} flex-items-block">
 			{{if .Issue.PullRequest.HasMerged}}
 				{{if .IsPullBranchDeletable}}
-					<div class="item item-section text gt-f1">
+					<div class="item item-section text tw-flex-1">
 						<div class="item-section-left">
 							<h3 class="gt-mb-3">
 								{{ctx.Locale.Tr "repo.pulls.merged_success"}}
@@ -48,7 +48,7 @@
 					</div>
 				{{end}}
 			{{else if .Issue.IsClosed}}
-				<div class="item item-section text gt-f1">
+				<div class="item item-section text tw-flex-1">
 					<div class="item-section-left">
 						<h3 class="gt-mb-3">{{ctx.Locale.Tr "repo.pulls.closed"}}</h3>
 						<div class="merge-section-info">
@@ -82,7 +82,7 @@
 				</div>
 			{{else if .IsPullWorkInProgress}}
 				<div class="item toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{.WorkInProgressPrefix}}" data-update-url="{{.Issue.Link}}/title">
-					<div class="item-section-left flex-text-inline gt-f1">
+					<div class="item-section-left flex-text-inline tw-flex-1">
 						{{svg "octicon-x"}}
 						{{ctx.Locale.Tr "repo.pulls.cannot_merge_work_in_progress"}}
 					</div>
diff --git a/templates/repo/issue/view_content/reference_issue_dialog.tmpl b/templates/repo/issue/view_content/reference_issue_dialog.tmpl
index b771e0890..5f338f676 100644
--- a/templates/repo/issue/view_content/reference_issue_dialog.tmpl
+++ b/templates/repo/issue/view_content/reference_issue_dialog.tmpl
@@ -2,7 +2,7 @@
 	<div class="header">
 		{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}
 	</div>
-	<div class="content" style="text-align:left">
+	<div class="content tw-text-left">
 		<form class="ui form form-fetch-action" action="{{printf "%s/issues/new" .Repository.Link}}" method="post">
 			{{.CsrfTokenHtml}}
 			<div class="ui segment content">
diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl
index 9dd49fd7e..1414ac45e 100644
--- a/templates/repo/issue/view_content/sidebar.tmpl
+++ b/templates/repo/issue/view_content/sidebar.tmpl
@@ -3,7 +3,7 @@
 	{{if .Issue.IsPull}}
 		<input id="reviewer_id" name="reviewer_id" type="hidden" value="{{.reviewer_id}}">
 		<div class="ui {{if or (and (not .Reviewers) (not .TeamReviewers)) (not .CanChooseReviewer) .Repository.IsArchived}}disabled{{end}} floating jump select-reviewers-modify dropdown">
-			<a class="text gt-df gt-ac muted">
+			<a class="text tw-flex tw-items-center muted">
 				<strong>{{ctx.Locale.Tr "repo.issues.review.reviewers"}}</strong>
 				{{if and .CanChooseReviewer (not .Repository.IsArchived)}}
 					{{svg "octicon-gear" 16 "gt-ml-2"}}
@@ -50,17 +50,17 @@
 			<span class="no-select item {{if or .OriginalReviews .PullReviewers}}gt-hidden{{end}}">{{ctx.Locale.Tr "repo.issues.new.no_reviewers"}}</span>
 			<div class="selected">
 				{{range .PullReviewers}}
-					<div class="item gt-df gt-ac gt-py-3">
-						<div class="gt-df gt-ac gt-f1">
+					<div class="item tw-flex tw-items-center gt-py-3">
+						<div class="tw-flex tw-items-center tw-flex-1">
 							{{if .User}}
 								<a class="muted sidebar-item-link" href="{{.User.HomeLink}}">{{ctx.AvatarUtils.Avatar .User 20 "gt-mr-3"}}{{.User.GetDisplayName}}</a>
 							{{else if .Team}}
 								<span class="text">{{svg "octicon-people" 20 "gt-mr-3"}}{{$.Issue.Repo.OwnerName}}/{{.Team.Name}}</span>
 							{{end}}
 						</div>
-						<div class="gt-df gt-ac gt-gap-3">
+						<div class="tw-flex tw-items-center tw-gap-2">
 							{{if (and $.Permission.IsAdmin (or (eq .Review.Type 1) (eq .Review.Type 3)) (not $.Issue.IsClosed))}}
-								<a href="#" class="ui muted icon gt-df gt-ac show-modal" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dismiss_review"}}" data-modal="#dismiss-review-modal-{{.Review.ID}}">
+								<a href="#" class="ui muted icon tw-flex tw-items-center show-modal" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dismiss_review"}}" data-modal="#dismiss-review-modal-{{.Review.ID}}">
 									{{svg "octicon-x" 20}}
 								</a>
 								<div class="ui small modal" id="dismiss-review-modal-{{.Review.ID}}">
@@ -99,14 +99,14 @@
 					</div>
 				{{end}}
 				{{range .OriginalReviews}}
-					<div class="item gt-df gt-ac gt-py-3">
-						<div class="gt-df gt-ac gt-f1">
+					<div class="item tw-flex tw-items-center gt-py-3">
+						<div class="tw-flex tw-items-center tw-flex-1">
 							<a class="muted" href="{{$.Repository.OriginalURL}}" data-tooltip-content="{{ctx.Locale.Tr "repo.migrated_from_fake" $.Repository.GetOriginalURLHostname}}">
 								{{svg (MigrationIcon $.Repository.GetOriginalURLHostname) 20 "gt-mr-3"}}
 								{{.OriginalAuthor}}
 							</a>
 						</div>
-						<div class="gt-df gt-ac gt-gap-3">
+						<div class="tw-flex tw-items-center tw-gap-2">
 							{{svg (printf "octicon-%s" .Type.Icon) 16 (printf "text %s" (.HTMLTypeColorName))}}
 						</div>
 					</div>
@@ -264,7 +264,7 @@
 
 	{{if .Participants}}
 		<span class="text"><strong>{{ctx.Locale.Tr "repo.issues.num_participants" .NumParticipants}}</strong></span>
-		<div class="ui list gt-df gt-fw">
+		<div class="ui list tw-flex tw-flex-wrap">
 			{{range .Participants}}
 				<a {{if gt .ID 0}}href="{{.HomeLink}}"{{end}} data-tooltip-content="{{.GetDisplayName}}">
 					{{ctx.AvatarUtils.Avatar . 28 "gt-my-1 gt-mr-2"}}
@@ -317,7 +317,7 @@
 						<div class="ui mini modal issue-start-time-modal">
 							<div class="header">{{ctx.Locale.Tr "repo.issues.add_time"}}</div>
 							<div class="content">
-								<form method="post" id="add_time_manual_form" action="{{.Issue.Link}}/times/add" class="ui input fluid gt-gap-3">
+								<form method="post" id="add_time_manual_form" action="{{.Issue.Link}}/times/add" class="ui input fluid tw-gap-2">
 									{{$.CsrfTokenHtml}}
 									<input placeholder='{{ctx.Locale.Tr "repo.issues.add_time_hours"}}' type="number" name="hours">
 									<input placeholder='{{ctx.Locale.Tr "repo.issues.add_time_minutes"}}' type="number" name="minutes" class="ui compact">
@@ -368,7 +368,7 @@
 		</div>
 		{{if ne .Issue.DeadlineUnix 0}}
 			<p>
-				<div class="gt-df gt-sb gt-ac">
+				<div class="tw-flex tw-justify-between tw-items-center">
 					<div class="due-date {{if .Issue.IsOverdue}}text red{{end}}" {{if .Issue.IsOverdue}}data-tooltip-content="{{ctx.Locale.Tr "repo.issues.due_date_overdue"}}"{{end}}>
 						{{svg "octicon-calendar" 16 "gt-mr-3"}}
 						{{DateTime "long" .Issue.DeadlineUnix.FormatDate}}
@@ -424,8 +424,8 @@
 				</span>
 				<div class="ui relaxed divided list">
 					{{range .BlockingDependencies}}
-						<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
-							<div class="item-left gt-df gt-jc gt-fc gt-f1 gt-ellipsis">
+						<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} tw-flex tw-items-center tw-justify-between">
+							<div class="item-left tw-flex tw-justify-center tw-flex-col tw-flex-1 gt-ellipsis">
 								<a class="title muted" href="{{.Issue.Link}}" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
 									#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
 								</a>
@@ -433,7 +433,7 @@
 									{{.Repository.OwnerName}}/{{.Repository.Name}}
 								</div>
 							</div>
-							<div class="item-right gt-df gt-ac gt-m-2">
+							<div class="item-right tw-flex tw-items-center gt-m-2">
 								{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
 									<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blocking" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
 										{{svg "octicon-trash" 16}}
@@ -443,7 +443,7 @@
 						</div>
 					{{end}}
 					{{if .BlockingDependenciesNotPermitted}}
-						<div class="item gt-df gt-ac gt-sb gt-ellipsis">
+						<div class="item tw-flex tw-items-center tw-justify-between gt-ellipsis">
 							<span>{{ctx.Locale.TrN (len .BlockingDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockingDependenciesNotPermitted)}}</span>
 						</div>
 					{{end}}
@@ -456,8 +456,8 @@
 				</span>
 				<div class="ui relaxed divided list">
 					{{range .BlockedByDependencies}}
-						<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
-							<div class="item-left gt-df gt-jc gt-fc gt-f1 gt-ellipsis">
+						<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} tw-flex tw-items-center tw-justify-between">
+							<div class="item-left tw-flex tw-justify-center tw-flex-col tw-flex-1 gt-ellipsis">
 								<a class="title muted" href="{{.Issue.Link}}" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
 									#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
 								</a>
@@ -465,7 +465,7 @@
 									{{.Repository.OwnerName}}/{{.Repository.Name}}
 								</div>
 							</div>
-							<div class="item-right gt-df gt-ac gt-m-2">
+							<div class="item-right tw-flex tw-items-center gt-m-2">
 								{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
 									<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blockedBy" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
 										{{svg "octicon-trash" 16}}
@@ -476,8 +476,8 @@
 					{{end}}
 					{{if $.CanCreateIssueDependencies}}
 						{{range .BlockedByDependenciesNotPermitted}}
-							<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
-								<div class="item-left gt-df gt-jc gt-fc gt-f1 gt-ellipsis">
+							<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} tw-flex tw-items-center tw-justify-between">
+								<div class="item-left tw-flex tw-justify-center tw-flex-col tw-flex-1 gt-ellipsis">
 									<div class="gt-ellipsis">
 										<span data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.no_permission.can_remove"}}">{{svg "octicon-lock" 16}}</span>
 										<span class="title" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
@@ -488,7 +488,7 @@
 										{{.Repository.OwnerName}}/{{.Repository.Name}}
 									</div>
 								</div>
-								<div class="item-right gt-df gt-ac gt-m-2">
+								<div class="item-right tw-flex tw-items-center gt-m-2">
 									{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
 										<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blocking" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
 											{{svg "octicon-trash" 16}}
@@ -498,7 +498,7 @@
 							</div>
 						{{end}}
 					{{else if .BlockedByDependenciesNotPermitted}}
-						<div class="item gt-df gt-ac gt-sb gt-ellipsis">
+						<div class="item tw-flex tw-items-center tw-justify-between gt-ellipsis">
 							<span>{{ctx.Locale.TrN (len .BlockedByDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockedByDependenciesNotPermitted)}}</span>
 						</div>
 					{{end}}
@@ -555,7 +555,7 @@
 	<div class="divider"></div>
 	<div class="ui equal width compact grid">
 		{{$issueReferenceLink := printf "%s#%d" .Issue.Repo.FullName .Issue.Index}}
-		<div class="row gt-ac" data-tooltip-content="{{$issueReferenceLink}}">
+		<div class="row tw-items-center" data-tooltip-content="{{$issueReferenceLink}}">
 			<span class="text column truncate">{{ctx.Locale.Tr "repo.issues.reference_link" $issueReferenceLink}}</span>
 			<button class="ui two wide button column gt-p-3" data-clipboard-text="{{$issueReferenceLink}}">{{svg "octicon-copy" 14}}</button>
 		</div>
diff --git a/templates/repo/issue/view_content/update_branch_by_merge.tmpl b/templates/repo/issue/view_content/update_branch_by_merge.tmpl
index 4dbefefe0..adce052de 100644
--- a/templates/repo/issue/view_content/update_branch_by_merge.tmpl
+++ b/templates/repo/issue/view_content/update_branch_by_merge.tmpl
@@ -7,7 +7,7 @@
 		</div>
 		<div class="item-section-right">
 			{{if and $.UpdateAllowed $.UpdateByRebaseAllowed}}
-				<div class="gt-dib">
+				<div class="tw-inline-block">
 					<div class="ui buttons update-button">
 						<button class="ui button" data-do="{{$.Link}}/update" data-redirect="{{$.Link}}">
 							<span class="button-text">
diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl
index 764a8b01a..f65a4ee08 100644
--- a/templates/repo/issue/view_title.tmpl
+++ b/templates/repo/issue/view_title.tmpl
@@ -8,7 +8,7 @@
 		<h1 class="gt-word-break">
 			<span id="issue-title">{{RenderIssueTitle $.Context .Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} <span class="index">#{{.Issue.Index}}</span>
 </span>
-			<div id="edit-title-input" class="ui input gt-f1 gt-hidden">
+			<div id="edit-title-input" class="ui input tw-flex-1 gt-hidden">
 				<input value="{{.Issue.Title}}" maxlength="255" autocomplete="off">
 			</div>
 		</h1>
diff --git a/templates/repo/migrate/migrate.tmpl b/templates/repo/migrate/migrate.tmpl
index 8ba567ee6..32465bc39 100644
--- a/templates/repo/migrate/migrate.tmpl
+++ b/templates/repo/migrate/migrate.tmpl
@@ -5,7 +5,7 @@
 			{{template "repo/migrate/helper" .}}
 			<div class="ui cards migrate-entries">
 				{{range .Services}}
-					<a class="ui card migrate-entry gt-df gt-ac" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}&org={{$.Org}}&mirror={{$.Mirror}}">
+					<a class="ui card migrate-entry tw-flex tw-items-center" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}&org={{$.Org}}&mirror={{$.Mirror}}">
 						{{if eq .Name "github"}}
 							{{svg "octicon-mark-github" 184 "gt-p-4"}}
 						{{else if eq .Name "gitlab"}}
diff --git a/templates/repo/projects/view.tmpl b/templates/repo/projects/view.tmpl
index 377a7ff79..eea1057a5 100644
--- a/templates/repo/projects/view.tmpl
+++ b/templates/repo/projects/view.tmpl
@@ -2,7 +2,7 @@
 <div role="main" aria-label="{{.Title}}" class="page-content repository projects view-project">
 	{{template "repo/header" .}}
 	<div class="ui container padded">
-		<div class="gt-df gt-sb gt-ac gt-mb-4">
+		<div class="tw-flex tw-justify-between tw-items-center gt-mb-4">
 			{{template "repo/issue/navbar" .}}
 			<a class="ui small primary button" href="{{.RepoLink}}/issues/new/choose?project={{.Project.ID}}">{{ctx.Locale.Tr "repo.issues.new"}}</a>
 		</div>
diff --git a/templates/repo/pulls/fork.tmpl b/templates/repo/pulls/fork.tmpl
index f0907f409..2cf0a85fc 100644
--- a/templates/repo/pulls/fork.tmpl
+++ b/templates/repo/pulls/fork.tmpl
@@ -37,7 +37,7 @@
 
 					<div class="inline field">
 						<label>{{ctx.Locale.Tr "repo.fork_from"}}</label>
-						<a href="{{.ForkRepo.Link}}" class="gt-dib">{{.ForkRepo.FullName}}</a>
+						<a href="{{.ForkRepo.Link}}" class="tw-inline-block">{{.ForkRepo.FullName}}</a>
 					</div>
 					<div class="inline required field {{if .Err_RepoName}}error{{end}}">
 						<label for="repo_name">{{ctx.Locale.Tr "repo.repo_name"}}</label>
diff --git a/templates/repo/pulls/tab_menu.tmpl b/templates/repo/pulls/tab_menu.tmpl
index 10bdfdb3d..0ddb17a93 100644
--- a/templates/repo/pulls/tab_menu.tmpl
+++ b/templates/repo/pulls/tab_menu.tmpl
@@ -15,7 +15,7 @@
 			{{ctx.Locale.Tr "repo.pulls.tab_files"}}
 			<span class="ui small label">{{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}}</span>
 		</a>
-		<span class="item gt-ml-auto gt-pr-0 gt-font-bold gt-df gt-ac gt-gap-3">
+		<span class="item tw-ml-auto gt-pr-0 tw-font-bold tw-flex tw-items-center tw-gap-2">
 			<span><span class="text green">{{if .Diff.TotalAddition}}+{{.Diff.TotalAddition}}{{end}}</span> <span class="text red">{{if .Diff.TotalDeletion}}-{{.Diff.TotalDeletion}}{{end}}</span></span>
 			<span class="diff-stats-bar">
 				<div class="diff-stats-add-bar" style="width: {{Eval 100 "*" .Diff.TotalAddition "/" "(" .Diff.TotalAddition "+" .Diff.TotalDeletion "+" 0.0 ")"}}%"></div>
diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl
index f1934493d..8c64380d4 100644
--- a/templates/repo/release/list.tmpl
+++ b/templates/repo/release/list.tmpl
@@ -16,10 +16,10 @@
 						{{end}}
 					</div>
 					<div class="ui twelve wide column detail">
-						<div class="gt-df gt-ac gt-sb gt-fw gt-mb-3">
+						<div class="tw-flex tw-items-center tw-justify-between tw-flex-wrap gt-mb-3">
 							<h4 class="release-list-title gt-word-break">
 								<a href="{{$.RepoLink}}/releases/tag/{{$release.TagName | PathEscapeSegments}}">{{$release.Title}}</a>
-								{{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "gt-df"}}
+								{{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}}
 								{{if $release.IsDraft}}
 									<span class="ui yellow label">{{ctx.Locale.Tr "repo.release.draft"}}</span>
 								{{else if $release.IsPrerelease}}
diff --git a/templates/repo/release/new.tmpl b/templates/repo/release/new.tmpl
index 30e783167..fd6338a70 100644
--- a/templates/repo/release/new.tmpl
+++ b/templates/repo/release/new.tmpl
@@ -21,7 +21,7 @@
 					{{else}}
 						<input id="tag-name" name="tag_name" value="{{.tag_name}}" aria-label="{{ctx.Locale.Tr "repo.release.tag_name"}}" placeholder="{{ctx.Locale.Tr "repo.release.tag_name"}}" autofocus required maxlength="255">
 						<input id="tag-name-editor" type="hidden" data-existing-tags="{{JsonUtils.EncodeToString .Tags}}" data-tag-helper="{{ctx.Locale.Tr "repo.release.tag_helper"}}" data-tag-helper-new="{{ctx.Locale.Tr "repo.release.tag_helper_new"}}" data-tag-helper-existing="{{ctx.Locale.Tr "repo.release.tag_helper_existing"}}">
-						<div id="tag-target-selector" class="gt-dib">
+						<div id="tag-target-selector" class="tw-inline-block">
 							<span class="at">@</span>
 							<div class="ui selection dropdown">
 								<input type="hidden" name="tag_target" value="{{.tag_target}}">
@@ -61,7 +61,7 @@
 				</div>
 				{{range .attachments}}
 					<div class="field flex-text-block" id="attachment-{{.ID}}">
-						<div class="flex-text-inline gt-f1">
+						<div class="flex-text-inline tw-flex-1">
 							<input name="attachment-edit-{{.UUID}}"  class="attachment_edit" required value="{{.Name}}">
 							<input name="attachment-del-{{.UUID}}" type="hidden" value="false">
 							<span class="ui text grey tw-whitespace-nowrap">{{.Size | FileSize}}</span>
@@ -101,7 +101,7 @@
 					</div>
 					<span class="help">{{ctx.Locale.Tr "repo.release.prerelease_helper"}}</span>
 					<div class="divider gt-mt-0"></div>
-					<div class="gt-df gt-je">
+					<div class="tw-flex tw-justify-end">
 						{{if .PageIsEditRelease}}
 							<a class="ui small button" href="{{.RepoLink}}/releases">
 								{{ctx.Locale.Tr "repo.release.cancel"}}
diff --git a/templates/repo/release_tag_header.tmpl b/templates/repo/release_tag_header.tmpl
index fe978a968..7a00cbe49 100644
--- a/templates/repo/release_tag_header.tmpl
+++ b/templates/repo/release_tag_header.tmpl
@@ -2,8 +2,8 @@
 {{$canReadCode := $.Permission.CanRead $.UnitTypeCode}}
 
 {{if $canReadReleases}}
-	<div class="gt-df">
-		<div class="gt-f1 gt-df gt-ac">
+	<div class="tw-flex">
+		<div class="tw-flex-1 tw-flex tw-items-center">
 			<h2 class="ui compact small menu header small-menu-items">
 				<a class="{{if and .PageIsReleaseList (not .PageIsSingleTag)}}active {{end}}item" href="{{.RepoLink}}/releases">{{ctx.Locale.PrettyNumber .NumReleases}} {{ctx.Locale.TrN .NumReleases "repo.release" "repo.releases"}}</a>
 				{{if $canReadCode}}
diff --git a/templates/repo/settings/branches.tmpl b/templates/repo/settings/branches.tmpl
index 73aff887f..ee6bdfbf2 100644
--- a/templates/repo/settings/branches.tmpl
+++ b/templates/repo/settings/branches.tmpl
@@ -12,11 +12,11 @@
 				<p>
 					{{ctx.Locale.Tr "repo.settings.default_branch_desc"}}
 				</p>
-				<form class="gt-df" action="{{.Link}}" method="post">
+				<form class="tw-flex" action="{{.Link}}" method="post">
 					{{.CsrfTokenHtml}}
 					<input type="hidden" name="action" value="default_branch">
 					{{if not .Repository.IsEmpty}}
-						<div class="ui dropdown selection search gt-f1 gt-mr-3 tw-max-w-96">
+						<div class="ui dropdown selection search tw-flex-1 gt-mr-3 tw-max-w-96">
 							{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 							<input type="hidden" name="branch" value="{{.Repository.DefaultBranch}}">
 							<div class="default text">{{.Repository.DefaultBranch}}</div>
@@ -41,7 +41,7 @@
 			<div class="ui attached segment">
 				<div class="flex-list">
 					{{range .ProtectedBranches}}
-						<div class="flex-item gt-ac">
+						<div class="flex-item tw-items-center">
 							<div class="flex-item-main">
 								<div class="flex-item-title">
 									<div class="ui basic primary label">{{.RuleName}}</div>
diff --git a/templates/repo/settings/collaboration.tmpl b/templates/repo/settings/collaboration.tmpl
index d7b5c96ba..2a4ec577e 100644
--- a/templates/repo/settings/collaboration.tmpl
+++ b/templates/repo/settings/collaboration.tmpl
@@ -7,7 +7,7 @@
 		<div class="ui attached segment">
 			<div class="flex-list">
 				{{range .Collaborators}}
-					<div class="flex-item gt-ac">
+					<div class="flex-item tw-items-center">
 						<div class="flex-item-leading">
 							<a href="{{.HomeLink}}">{{ctx.AvatarUtils.Avatar . 32}}</a>
 						</div>
@@ -41,7 +41,7 @@
 		<div class="ui bottom attached segment">
 			<form class="ui form" id="repo-collab-form" action="{{.Link}}" method="post">
 				{{.CsrfTokenHtml}}
-				<div id="search-user-box" class="ui search input gt-vm">
+				<div id="search-user-box" class="ui search input tw-align-middle">
 					<input class="prompt" name="collaborator" placeholder="{{ctx.Locale.Tr "search.team_kind"}}" autocomplete="off" autofocus required>
 				</div>
 				<button class="ui primary button">{{ctx.Locale.Tr "repo.settings.add_collaborator"}}</button>
@@ -89,7 +89,7 @@
 			{{if $allowedToChangeTeams}}
 				<form class="ui form" id="repo-collab-team-form" action="{{.Link}}/team" method="post">
 					{{.CsrfTokenHtml}}
-					<div id="search-team-box" class="ui search input gt-vm" data-org-name="{{.OrgName}}">
+					<div id="search-team-box" class="ui search input tw-align-middle" data-org-name="{{.OrgName}}">
 						<input class="prompt" name="team" placeholder="{{ctx.Locale.Tr "search.team_kind"}}" autocomplete="off" autofocus required>
 					</div>
 					<button class="ui primary button">{{ctx.Locale.Tr "repo.settings.add_team"}}</button>
diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl
index a79a19682..f66b94c33 100644
--- a/templates/repo/settings/deploy_keys.tmpl
+++ b/templates/repo/settings/deploy_keys.tmpl
@@ -31,7 +31,7 @@
 							<label for="is_writable">
 								{{ctx.Locale.Tr "repo.settings.is_writable"}}
 							</label>
-							<small style="padding-left: 26px;">{{ctx.Locale.Tr "repo.settings.is_writable_info"}}</small>
+							<small class="tw-pl-[26px]">{{ctx.Locale.Tr "repo.settings.is_writable_info"}}</small>
 						</div>
 					</div>
 					<button class="ui primary button">
diff --git a/templates/repo/settings/githooks.tmpl b/templates/repo/settings/githooks.tmpl
index 3fce29d54..3d15d097c 100644
--- a/templates/repo/settings/githooks.tmpl
+++ b/templates/repo/settings/githooks.tmpl
@@ -11,7 +11,7 @@
 				{{range .Hooks}}
 					<div class="item truncated-item-container">
 						<span class="text {{if .IsActive}}green{{else}}grey{{end}} gt-mr-3">{{svg "octicon-dot-fill" 22}}</span>
-						<span class="text truncate gt-f1 gt-mr-3">{{.Name}}</span>
+						<span class="text truncate tw-flex-1 gt-mr-3">{{.Name}}</span>
 						<a class="muted tw-float-right gt-p-3" href="{{$.RepoLink}}/settings/hooks/git/{{.Name|PathEscape}}">
 							{{svg "octicon-pencil"}}
 						</a>
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index 99d75b8a8..7827f0b63 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -110,19 +110,18 @@
 					<table class="ui table">
 						<thead>
 							<tr>
-								<th style="width:40%">{{ctx.Locale.Tr "repo.settings.mirror_settings.mirrored_repository"}}</th>
+								<th class="tw-w-2/5">{{ctx.Locale.Tr "repo.settings.mirror_settings.mirrored_repository"}}</th>
 								<th>{{ctx.Locale.Tr "repo.settings.mirror_settings.direction"}}</th>
 								<th>{{ctx.Locale.Tr "repo.settings.mirror_settings.last_update"}}</th>
 								<th></th>
 							</tr>
 						</thead>
-						{{end}}
 						{{if $modifyBrokenPullMirror}}
 							{{/* even if a repo is a pull mirror (IsMirror=true), the PullMirror might still be nil if the mirror migration is broken */}}
 							<tbody>
 								<tr>
 									<td colspan="4">
-										<div class="text red gt-py-4 gt-border-secondary-bottom">{{ctx.Locale.Tr "repo.settings.mirror_settings.direction.pull"}}: {{ctx.Locale.Tr "error.occurred"}}</div>
+										<div class="text red gt-py-4">{{ctx.Locale.Tr "repo.settings.mirror_settings.direction.pull"}}: {{ctx.Locale.Tr "error.occurred"}}</div>
 									</td>
 								</tr>
 							</tbody>
@@ -133,7 +132,7 @@
 								<td>{{ctx.Locale.Tr "repo.settings.mirror_settings.direction.pull"}}</td>
 								<td>{{DateTime "full" .PullMirror.UpdatedUnix}}</td>
 								<td class="right aligned">
-									<form method="post" class="gt-dib">
+									<form method="post" class="tw-inline-block">
 										{{.CsrfTokenHtml}}
 										<input type="hidden" name="action" value="mirror-sync">
 										<button class="ui primary tiny button inline text-thin">{{ctx.Locale.Tr "repo.settings.sync_mirror"}}</button>
@@ -201,13 +200,14 @@
 								</td>
 							</tr>
 						</tbody>
+						{{end}}{{/* end if: $modifyBrokenPullMirror / $isWorkingPullMirror */}}
 					</table>
-					{{end}}{{/* end if: IsMirror */}}
+					{{end}}{{/* end if .Repository.IsMirror */}}
 
 					<table class="ui table">
 						<thead>
 							<tr>
-								<th style="width:40%">{{ctx.Locale.Tr "repo.settings.mirror_settings.pushed_repository"}}</th>
+								<th class="tw-w-2/5">{{ctx.Locale.Tr "repo.settings.mirror_settings.pushed_repository"}}</th>
 								<th>{{ctx.Locale.Tr "repo.settings.mirror_settings.direction"}}</th>
 								<th>{{ctx.Locale.Tr "repo.settings.mirror_settings.last_update"}}</th>
 								<th></th>
@@ -230,13 +230,13 @@
 									>
 										{{svg "octicon-pencil" 14}}
 									</button>
-									<form method="post" class="gt-dib">
+									<form method="post" class="tw-inline-block">
 										{{$.CsrfTokenHtml}}
 										<input type="hidden" name="action" value="push-mirror-sync">
 										<input type="hidden" name="push_mirror_id" value="{{.ID}}">
 										<button class="ui primary tiny button" data-tooltip-content="{{ctx.Locale.Tr "repo.settings.sync_mirror"}}">{{svg "octicon-sync" 14}}</button>
 									</form>
-									<form method="post" class="gt-dib">
+									<form method="post" class="tw-inline-block">
 										{{$.CsrfTokenHtml}}
 										<input type="hidden" name="action" value="push-mirror-remove">
 										<input type="hidden" name="push_mirror_id" value="{{.ID}}">
@@ -492,7 +492,7 @@
 					</div>
 				</div>
 				{{if not .Repository.IsMirror}}
-					<div class="flex-item gt-ac">
+					<div class="flex-item tw-items-center">
 						<div class="flex-item-main">
 							{{if .Repository.IsArchived}}
 								<div class="flex-item-title">{{ctx.Locale.Tr "repo.settings.unarchive.header"}}</div>
diff --git a/templates/repo/settings/tags.tmpl b/templates/repo/settings/tags.tmpl
index 4c196f0f9..c9efb7b67 100644
--- a/templates/repo/settings/tags.tmpl
+++ b/templates/repo/settings/tags.tmpl
@@ -106,7 +106,7 @@
 										</td>
 										<td class="right aligned">
 											<a class="ui tiny primary button" href="{{$.RepoLink}}/settings/tags/{{.ID}}">{{ctx.Locale.Tr "edit"}}</a>
-											<form class="gt-dib" action="{{$.RepoLink}}/settings/tags/delete" method="post">
+											<form class="tw-inline-block" action="{{$.RepoLink}}/settings/tags/delete" method="post">
 												{{$.CsrfTokenHtml}}
 												<input type="hidden" name="id" value="{{.ID}}">
 												<button class="ui tiny red button">{{ctx.Locale.Tr "remove"}}</button>
diff --git a/templates/repo/settings/webhook/base_list.tmpl b/templates/repo/settings/webhook/base_list.tmpl
index e56929b70..9abc03e40 100644
--- a/templates/repo/settings/webhook/base_list.tmpl
+++ b/templates/repo/settings/webhook/base_list.tmpl
@@ -15,7 +15,7 @@
 		{{range .Webhooks}}
 			<div class="item truncated-item-container">
 				<span class="text {{if eq .LastStatus 1}}green{{else if eq .LastStatus 2}}red{{else}}grey{{end}} gt-mr-3">{{svg "octicon-dot-fill" 22}}</span>
-				<div class="text truncate gt-f1 gt-mr-3">
+				<div class="text truncate tw-flex-1 gt-mr-3">
 					<a title="{{.URL}}" href="{{$.BaseLink}}/{{.ID}}">{{.URL}}</a>
 				</div>
 				<a class="muted gt-p-3" href="{{$.BaseLink}}/{{.ID}}">{{svg "octicon-pencil"}}</a>
diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl
index 4e0f0e9c3..e2aee1394 100644
--- a/templates/repo/settings/webhook/history.tmpl
+++ b/templates/repo/settings/webhook/history.tmpl
@@ -6,7 +6,9 @@
 			<div class="ui right">
 				<!-- the button is wrapped with a span because the tooltip doesn't show on hover if we put data-tooltip-content directly on the button -->
 				<span data-tooltip-content="{{if or $isNew .Webhook.IsActive}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc"}}{{else}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc_disabled"}}{{end}}">
-					<button class="ui teal tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test" data-redirect="{{.Link}}">{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}</button>
+					<button class="ui teal tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test" data-redirect="{{.Link}}">
+						<span class="text">{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}</span>
+					</button>
 			</span>
 			</div>
 		{{end}}
@@ -15,7 +17,7 @@
 		<div class="ui list">
 			{{range .History}}
 				<div class="item">
-					<div class="flex-text-block gt-sb">
+					<div class="flex-text-block tw-justify-between">
 						<div class="flex-text-inline">
 							{{if .IsSucceed}}
 								<span class="text green">{{svg "octicon-check"}}</span>
diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl
index 8edb0c151..654a65fa5 100644
--- a/templates/repo/sub_menu.tmpl
+++ b/templates/repo/sub_menu.tmpl
@@ -25,7 +25,7 @@
 		{{range .LanguageStats}}
 		<div class="item">
 			<i class="color-icon" style="background-color: {{.Color}}"></i>
-			<span class="gt-font-semibold">
+			<span class="tw-font-semibold">
 				{{if eq .Language "other"}}
 					{{ctx.Locale.Tr "repo.language_other"}}
 				{{else}}
diff --git a/templates/repo/tag/list.tmpl b/templates/repo/tag/list.tmpl
index 9f0676e39..06c02c5f7 100644
--- a/templates/repo/tag/list.tmpl
+++ b/templates/repo/tag/list.tmpl
@@ -5,7 +5,7 @@
 		{{template "base/alert" .}}
 		{{template "repo/release_tag_header" .}}
 		<h4 class="ui top attached header">
-			<div class="five wide column gt-df gt-ac">
+			<div class="five wide column tw-flex tw-items-center">
 				{{svg "octicon-tag" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.release.tags"}}
 			</div>
 		</h4>
@@ -18,12 +18,12 @@
 							<td class="tag">
 								<h3 class="release-tag-name gt-mb-3">
 									{{if $canReadReleases}}
-										<a class="gt-df gt-ac" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
+										<a class="tw-flex tw-items-center" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
 									{{else}}
-										<a class="gt-df gt-ac" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
+										<a class="tw-flex tw-items-center" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a>
 									{{end}}
 								</h3>
-								<div class="download gt-df gt-ac">
+								<div class="download tw-flex tw-items-center">
 									{{if $.Permission.CanRead $.UnitTypeCode}}
 										{{if .CreatedUnix}}
 											<span class="gt-mr-3">{{svg "octicon-clock" 16 "gt-mr-2"}}{{TimeSinceUnix .CreatedUnix ctx.Locale}}</span>
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl
index 851e67db6..cbc3bdf67 100644
--- a/templates/repo/view_file.tmpl
+++ b/templates/repo/view_file.tmpl
@@ -25,8 +25,8 @@
 		</div>
 	{{end}}
 
-	<h4 class="file-header ui top attached header gt-df gt-ac gt-sb gt-fw">
-		<div class="file-header-left gt-df gt-ac gt-py-3 gt-pr-4">
+	<h4 class="file-header ui top attached header tw-flex tw-items-center tw-justify-between tw-flex-wrap">
+		<div class="file-header-left tw-flex tw-items-center gt-py-3 gt-pr-4">
 			{{if .ReadmeInList}}
 				{{svg "octicon-book" 16 "gt-mr-3"}}
 				<strong><a class="default-link muted" href="#readme">{{.FileName}}</a></strong>
@@ -34,10 +34,10 @@
 				{{template "repo/file_info" .}}
 			{{end}}
 		</div>
-		<div class="file-header-right file-actions gt-df gt-ac gt-fw">
+		<div class="file-header-right file-actions tw-flex tw-items-center tw-flex-wrap">
 			{{if .HasSourceRenderedToggle}}
 				<div class="ui compact icon buttons">
-					<a href="{{$.Link}}?display=source" class="ui mini basic button {{if .IsDisplayingSource}}active{{end}}" data-tooltip-content="{{ctx.Locale.Tr "repo.file_view_source"}}">{{svg "octicon-code" 15}}</a>
+					<a href="?display=source" class="ui mini basic button {{if .IsDisplayingSource}}active{{end}}" data-tooltip-content="{{ctx.Locale.Tr "repo.file_view_source"}}">{{svg "octicon-code" 15}}</a>
 					<a href="{{$.Link}}" class="ui mini basic button {{if .IsDisplayingRendered}}active{{end}}" data-tooltip-content="{{ctx.Locale.Tr "repo.file_view_rendered"}}">{{svg "octicon-file" 15}}</a>
 				</div>
 			{{end}}
diff --git a/templates/repo/wiki/new.tmpl b/templates/repo/wiki/new.tmpl
index 0d0e78c7a..0e929f24e 100644
--- a/templates/repo/wiki/new.tmpl
+++ b/templates/repo/wiki/new.tmpl
@@ -3,13 +3,13 @@
 	{{template "repo/header" .}}
 	<div class="ui container">
 		{{template "base/alert" .}}
-		<div class="ui header flex-text-block gt-sb">
+		<div class="ui header flex-text-block tw-justify-between">
 			{{ctx.Locale.Tr "repo.wiki.new_page"}}
 			{{if .PageIsWikiEdit}}
 				<a class="ui tiny primary button" href="{{.RepoLink}}/wiki?action=_new">{{ctx.Locale.Tr "repo.wiki.new_page_button"}}</a>
 			{{end}}
 		</div>
-		<form class="ui form" action="{{.Link}}?action={{if .PageIsWikiEdit}}_edit{{else}}_new{{end}}" method="post">
+		<form class="ui form" action="?action={{if .PageIsWikiEdit}}_edit{{else}}_new{{end}}" method="post">
 			{{.CsrfTokenHtml}}
 			<div class="field {{if .Err_Title}}error{{end}}">
 				<input name="title" value="{{.title}}" aria-label="{{ctx.Locale.Tr "repo.wiki.page_title"}}" placeholder="{{ctx.Locale.Tr "repo.wiki.page_title"}}" autofocus required>
diff --git a/templates/repo/wiki/pages.tmpl b/templates/repo/wiki/pages.tmpl
index 22eb2619f..42c36a9f4 100644
--- a/templates/repo/wiki/pages.tmpl
+++ b/templates/repo/wiki/pages.tmpl
@@ -2,7 +2,7 @@
 <div role="main" aria-label="{{.Title}}" class="page-content repository wiki pages">
 	{{template "repo/header" .}}
 	<div class="ui container">
-		<h2 class="ui header gt-df gt-ac gt-sb">
+		<h2 class="ui header tw-flex tw-items-center tw-justify-between">
 			<span>{{ctx.Locale.Tr "repo.wiki.pages"}}</span>
 			<span>
 				{{if and .CanWriteWiki (not .Repository.IsMirror)}}
diff --git a/templates/repo/wiki/revision.tmpl b/templates/repo/wiki/revision.tmpl
index 647c331d5..182635e01 100644
--- a/templates/repo/wiki/revision.tmpl
+++ b/templates/repo/wiki/revision.tmpl
@@ -15,7 +15,7 @@
 				</div>
 			</div>
 			<div class="ui eight wide column text right">
-				<div class="ui action small input" id="clone-panel">
+				<div class="clone-panel ui action small input">
 					{{template "repo/clone_buttons" .}}
 					{{template "repo/clone_script" .}}
 				</div>
diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl
index 541b1e9b4..ebd7f2513 100644
--- a/templates/repo/wiki/view.tmpl
+++ b/templates/repo/wiki/view.tmpl
@@ -4,7 +4,7 @@
 	{{$title := .title}}
 	<div class="ui container">
 		<div class="repo-button-row">
-			<div class="gt-df gt-ac">
+			<div class="tw-flex tw-items-center">
 				<div class="ui floating filter dropdown" data-no-results="{{ctx.Locale.Tr "repo.pulls.no_results"}}">
 					<div class="ui basic small button">
 						<span class="text">
@@ -28,7 +28,7 @@
 					</div>
 				</div>
 			</div>
-			<div class="ui action small input gt-df gt-ac" id="clone-panel">
+			<div class="clone-panel ui action small input">
 				{{template "repo/clone_buttons" .}}
 				{{template "repo/clone_script" .}}
 			</div>
diff --git a/templates/shared/actions/runner_edit.tmpl b/templates/shared/actions/runner_edit.tmpl
index fbc730b28..f8bbf23b6 100644
--- a/templates/shared/actions/runner_edit.tmpl
+++ b/templates/shared/actions/runner_edit.tmpl
@@ -7,15 +7,15 @@
 			{{template "base/disable_form_autofill"}}
 			{{.CsrfTokenHtml}}
 			<div class="runner-basic-info">
-				<div class="field gt-dib gt-mr-4">
+				<div class="field tw-inline-block gt-mr-4">
 					<label>{{ctx.Locale.Tr "actions.runners.status"}}</label>
 					<span class="ui {{if .Runner.IsOnline}}green{{else}}basic{{end}} label">{{.Runner.StatusLocaleName ctx.Locale}}</span>
 				</div>
-				<div class="field gt-dib gt-mr-4">
+				<div class="field tw-inline-block gt-mr-4">
 					<label>{{ctx.Locale.Tr "actions.runners.last_online"}}</label>
 					<span>{{if .Runner.LastOnline}}{{TimeSinceUnix .Runner.LastOnline ctx.Locale}}{{else}}{{ctx.Locale.Tr "never"}}{{end}}</span>
 				</div>
-				<div class="field gt-dib gt-mr-4">
+				<div class="field tw-inline-block gt-mr-4">
 					<label>{{ctx.Locale.Tr "actions.runners.labels"}}</label>
 					<span>
 						{{range .Runner.AgentLabels}}
@@ -23,7 +23,7 @@
 						{{end}}
 					</span>
 				</div>
-				<div class="field gt-dib gt-mr-4">
+				<div class="field tw-inline-block gt-mr-4">
 					<label>{{ctx.Locale.Tr "actions.runners.owner_type"}}</label>
 					<span data-tooltip-content="{{.Runner.BelongsToOwnerName}}">{{.Runner.BelongsToOwnerType.LocaleString ctx.Locale}}</span>
 				</div>
diff --git a/templates/shared/issueicon.tmpl b/templates/shared/issueicon.tmpl
index 089e80bd8..a62714e98 100644
--- a/templates/shared/issueicon.tmpl
+++ b/templates/shared/issueicon.tmpl
@@ -1,15 +1,15 @@
 {{if .IsPull}}
-	{{if and .PullRequest .PullRequest.HasMerged}}
-		{{svg "octicon-git-merge" 16 "text purple"}}
-	{{else if and (.GetPullRequest ctx) (.GetPullRequest ctx).HasMerged}}
-		{{svg "octicon-git-merge" 16 "text purple"}}
+	{{if not .PullRequest}}
+		No PullRequest
 	{{else}}
 		{{if .IsClosed}}
-			{{svg "octicon-git-pull-request" 16 "text red"}}
+			{{if .PullRequest.HasMerged}}
+				{{svg "octicon-git-merge" 16 "text purple"}}
+			{{else}}
+				{{svg "octicon-git-pull-request" 16 "text red"}}
+			{{end}}
 		{{else}}
-			{{if and .PullRequest (.PullRequest.IsWorkInProgress ctx)}}
-				{{svg "octicon-git-pull-request-draft" 16 "text grey"}}
-			{{else if and (.GetPullRequest ctx) ((.GetPullRequest ctx).IsWorkInProgress ctx)}}
+			{{if .PullRequest.IsWorkInProgress ctx}}
 				{{svg "octicon-git-pull-request-draft" 16 "text grey"}}
 			{{else}}
 				{{svg "octicon-git-pull-request" 16 "text green"}}
diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl
index 2969efa6b..639221abb 100644
--- a/templates/shared/issuelist.tmpl
+++ b/templates/shared/issuelist.tmpl
@@ -21,7 +21,7 @@
 						{{end}}
 						<span class="labels-list gt-ml-2">
 							{{range .Labels}}
-								<a href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{RenderLabel $.Context .}}</a>
+								<a href="?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{RenderLabel $.Context .}}</a>
 							{{end}}
 						</span>
 					</div>
diff --git a/templates/shared/repo_search.tmpl b/templates/shared/repo_search.tmpl
index 40cc2292d..d2fe2de14 100644
--- a/templates/shared/repo_search.tmpl
+++ b/templates/shared/repo_search.tmpl
@@ -1,5 +1,5 @@
 <div class="ui small secondary filter menu">
-	<form id="repo-search-form" class="ui form ignore-dirty tw-flex-1 tw-flex tw-flex-row tw-gap-x-2 gt-ac">
+	<form id="repo-search-form" class="ui form ignore-dirty tw-flex-1 tw-flex tw-flex-row tw-gap-x-2 tw-items-center">
 		{{if .Language}}<input hidden name="language" value="{{.Language}}">{{end}}
 		{{if .TopicOnly}}<input hidden name="topic" value="{{.TopicOnly}}">{{end}}
 		<div class="ui small fluid action input tw-flex-1">
diff --git a/templates/shared/search/code/results.tmpl b/templates/shared/search/code/results.tmpl
index 02d125277..a22820e78 100644
--- a/templates/shared/search/code/results.tmpl
+++ b/templates/shared/search/code/results.tmpl
@@ -1,7 +1,7 @@
-<div class="flex-text-block gt-fw">
+<div class="flex-text-block tw-flex-wrap">
 	{{range $term := .SearchResultLanguages}}
 	<a class="ui {{if eq $.Language $term.Language}}primary{{end}} basic label gt-m-0"
-		href="{{$.Link}}?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}&fuzzy={{$.IsFuzzy}}">
+		href="?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}&fuzzy={{$.IsFuzzy}}">
 		<i class="color-icon gt-mr-3" style="background-color: {{$term.Color}}"></i>
 		{{$term.Language}}
 		<div class="detail">{{$term.Count}}</div>
@@ -12,9 +12,9 @@
 	{{range $result := .SearchResults}}
 		{{$repo := or $.Repo (index $.RepoMaps .RepoID)}}
 		<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
-			<h4 class="ui top attached normal header gt-df gt-fw">
+			<h4 class="ui top attached normal header tw-flex tw-flex-wrap">
 				{{if not $.Repo}}
-					<span class="file gt-f1">
+					<span class="file tw-flex-1">
 						<a rel="nofollow" href="{{$repo.Link}}">{{$repo.FullName}}</a>
 						{{if $repo.IsArchived}}
 							<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.archived"}}</span>
@@ -22,7 +22,7 @@
 						- {{.Filename}}
 					</span>
 				{{else}}
-					<span class="file gt-f1">{{.Filename}}</span>
+					<span class="file tw-flex-1">{{.Filename}}</span>
 				{{end}}
 				<a role="button" class="ui basic tiny button" rel="nofollow" href="{{$repo.Link}}/src/{{if $.CodeIndexerDisabled}}branch{{else}}commit{{end}}/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{ctx.Locale.Tr "repo.diff.view_file"}}</a>
 			</h4>
diff --git a/templates/shared/searchbottom.tmpl b/templates/shared/searchbottom.tmpl
index b123b497c..43d6092e8 100644
--- a/templates/shared/searchbottom.tmpl
+++ b/templates/shared/searchbottom.tmpl
@@ -1,5 +1,5 @@
-<div class="ui bottom attached table segment gt-df gt-ac gt-sb">
-		<div class="gt-df gt-ac gt-ml-4">
+<div class="ui bottom attached table segment tw-flex tw-items-center tw-justify-between">
+		<div class="tw-flex tw-items-center gt-ml-4">
 			{{if .result.Language}}
 					<i class="color-icon gt-mr-3" style="background-color: {{.result.Color}}"></i>{{.result.Language}}
 			{{end}}
diff --git a/templates/shared/secrets/add_list.tmpl b/templates/shared/secrets/add_list.tmpl
index 4fbd8ddcf..c943a1944 100644
--- a/templates/shared/secrets/add_list.tmpl
+++ b/templates/shared/secrets/add_list.tmpl
@@ -14,7 +14,7 @@
 	{{if .Secrets}}
 	<div class="flex-list">
 		{{range .Secrets}}
-		<div class="flex-item gt-ac">
+		<div class="flex-item tw-items-center">
 			<div class="flex-item-leading">
 				{{svg "octicon-key" 32}}
 			</div>
diff --git a/templates/shared/user/authorlink.tmpl b/templates/shared/user/authorlink.tmpl
index 64ccc62cd..4d8ad736b 100644
--- a/templates/shared/user/authorlink.tmpl
+++ b/templates/shared/user/authorlink.tmpl
@@ -1 +1 @@
-<a class="author text black gt-font-semibold muted"{{if gt .ID 0}} href="{{.HomeLink}}"{{end}}>{{.GetDisplayName}}</a>{{if .IsBot}}<span class="ui basic label gt-p-2">bot</span>{{end}}
+<a class="author text black tw-font-semibold muted"{{if gt .ID 0}} href="{{.HomeLink}}"{{end}}>{{.GetDisplayName}}</a>{{if .IsBot}}<span class="ui basic label gt-p-2">bot</span>{{end}}
diff --git a/templates/shared/user/org_profile_avatar.tmpl b/templates/shared/user/org_profile_avatar.tmpl
index a8846b0ab..2ff1e40ca 100644
--- a/templates/shared/user/org_profile_avatar.tmpl
+++ b/templates/shared/user/org_profile_avatar.tmpl
@@ -2,7 +2,7 @@
 	<div class="ui container">
 		<div class="ui vertically grid head">
 			<div class="column">
-				<div class="ui header gt-df gt-ac gt-word-break">
+				<div class="ui header tw-flex tw-items-center gt-word-break">
 					{{ctx.AvatarUtils.Avatar . 100}}
 					<span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span>
 					<span class="org-visibility">
diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl
index 4e25a5373..b1c837d36 100644
--- a/templates/shared/user/profile_big_avatar.tmpl
+++ b/templates/shared/user/profile_big_avatar.tmpl
@@ -1,5 +1,5 @@
 <div id="profile-avatar-card" class="ui card">
-	<div id="profile-avatar" class="content gt-df">
+	<div id="profile-avatar" class="content tw-flex">
 	{{if eq .SignedUserID .ContextUser.ID}}
 		<a class="image" href="{{AppSubUrl}}/user/settings" data-tooltip-content="{{ctx.Locale.Tr "user.change_avatar"}}">
 			{{/* the size doesn't take affect (and no need to take affect), image size(width) should be controlled by the parent container since this is not a flex layout*/}}
@@ -30,7 +30,7 @@
 			{{if .ContextUser.Location}}
 				<li>
 					{{svg "octicon-location"}}
-					<span class="gt-f1">{{.ContextUser.Location}}</span>
+					<span class="tw-flex-1">{{.ContextUser.Location}}</span>
 					{{if .ContextUserLocationMapURL}}
 						<a href="{{.ContextUserLocationMapURL}}" rel="nofollow noreferrer" data-tooltip-content="{{ctx.Locale.Tr "user.show_on_map"}}">
 							{{svg "octicon-link-external"}}
@@ -41,7 +41,7 @@
 			{{if (eq .SignedUserID .ContextUser.ID)}}
 				<li>
 					{{svg "octicon-mail"}}
-					<a class="gt-f1" href="mailto:{{.ContextUser.Email}}" rel="nofollow">{{.ContextUser.Email}}</a>
+					<a class="tw-flex-1" href="mailto:{{.ContextUser.Email}}" rel="nofollow">{{.ContextUser.Email}}</a>
 					<a href="{{AppSubUrl}}/user/settings#privacy-user-settings">
 						{{if .ShowUserEmail}}
 							<i data-tooltip-content="{{ctx.Locale.Tr "user.email_visibility.limited"}}">
diff --git a/templates/shared/variables/variable_list.tmpl b/templates/shared/variables/variable_list.tmpl
index 8e262d016..fc2ac98e2 100644
--- a/templates/shared/variables/variable_list.tmpl
+++ b/templates/shared/variables/variable_list.tmpl
@@ -16,7 +16,7 @@
 	{{if .Variables}}
 	<div class="flex-list">
 		{{range .Variables}}
-		<div class="flex-item gt-ac">
+		<div class="flex-item tw-items-center">
 			<div class="flex-item-leading">
 				{{svg "octicon-pencil" 32}}
 			</div>
diff --git a/templates/status/500.tmpl b/templates/status/500.tmpl
index 98e3044db..a75c76916 100644
--- a/templates/status/500.tmpl
+++ b/templates/status/500.tmpl
@@ -16,9 +16,9 @@
 </head>
 <body>
 	<div class="full height">
-		<nav class="ui secondary menu gt-border-secondary-bottom">
-			<div class="ui container gt-df">
-				<div class="item gt-f1">
+		<nav class="ui secondary menu">
+			<div class="ui container tw-flex">
+				<div class="item tw-flex-1">
 					<a href="{{AppSubUrl}}/" aria-label="{{ctx.Locale.Tr "home"}}">
 						<img width="30" height="30" src="{{AssetUrlPrefix}}/img/logo.svg" alt="{{ctx.Locale.Tr "logo"}}" aria-hidden="true">
 					</a>
@@ -28,6 +28,7 @@
 				</div>
 			</div>
 		</nav>
+		<div class="divider gt-my-0"></div>
 		<div role="main" class="page-content status-page-500">
 			<div class="ui container" >
 				<style> .ui.message.flash-message { text-align: left; } </style>
diff --git a/templates/user/auth/reset_passwd.tmpl b/templates/user/auth/reset_passwd.tmpl
index 4d569e206..f8303feef 100644
--- a/templates/user/auth/reset_passwd.tmpl
+++ b/templates/user/auth/reset_passwd.tmpl
@@ -51,7 +51,7 @@
 						<div class="inline field">
 							<button class="ui primary button">{{ctx.Locale.Tr "auth.reset_password_helper"}}</button>
 							{{if and .has_two_factor (not .scratch_code)}}
-								<a href="{{.Link}}?code={{.Code}}&amp;scratch_code=true">{{ctx.Locale.Tr "auth.use_scratch_code"}}</a>
+								<a href="?code={{.Code}}&scratch_code=true">{{ctx.Locale.Tr "auth.use_scratch_code"}}</a>
 							{{end}}
 						</div>
 					{{else}}
diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl
index d7d3649a4..ad86b0b88 100644
--- a/templates/user/auth/signin_inner.tmpl
+++ b/templates/user/auth/signin_inner.tmpl
@@ -54,10 +54,10 @@
 		{{ctx.Locale.Tr "sign_in_or"}}
 	</div>
 	<div id="oauth2-login-navigator" class="gt-py-2">
-		<div class="gt-df gt-fc gt-jc">
-			<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
+		<div class="tw-flex tw-flex-col tw-justify-center">
+			<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">
 				{{range $provider := .OAuth2Providers}}
-					<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
+					<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center gt-py-3 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
 						{{$provider.IconHTML 28}}
 						{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
 					</a>
diff --git a/templates/user/auth/signup_inner.tmpl b/templates/user/auth/signup_inner.tmpl
index cfd826a0c..26d9091b6 100644
--- a/templates/user/auth/signup_inner.tmpl
+++ b/templates/user/auth/signup_inner.tmpl
@@ -59,10 +59,10 @@
 				{{ctx.Locale.Tr "sign_in_or"}}
 			</div>
 			<div id="oauth2-login-navigator" class="gt-py-2">
-				<div class="gt-df gt-fc gt-jc">
-					<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
+				<div class="tw-flex tw-flex-col tw-justify-center">
+					<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">
 						{{range $provider := .OAuth2Providers}}
-							<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
+							<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center gt-py-3 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
 								{{$provider.IconHTML 28}}
 								{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
 							</a>
diff --git a/templates/user/auth/webauthn.tmpl b/templates/user/auth/webauthn.tmpl
index 722da02f5..24dd75eed 100644
--- a/templates/user/auth/webauthn.tmpl
+++ b/templates/user/auth/webauthn.tmpl
@@ -10,8 +10,8 @@
 				{{template "base/alert" .}}
 				<p>{{ctx.Locale.Tr "webauthn_sign_in"}}</p>
 			</div>
-			<div class="ui attached segment gt-df gt-ac gt-jc gt-gap-2 gt-py-3">
-				<div class="is-loading" style="width: 40px; height: 40px"></div>
+			<div class="ui attached segment tw-flex tw-items-center tw-justify-center tw-gap-1 gt-py-3">
+				<div class="is-loading tw-w-[40px] tw-h-[40px]"></div>
 				{{ctx.Locale.Tr "webauthn_press_button"}}
 			</div>
 			{{if .HasTwoFactor}}
diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl
index 0e7371ad8..fbe151607 100644
--- a/templates/user/dashboard/feeds.tmpl
+++ b/templates/user/dashboard/feeds.tmpl
@@ -4,7 +4,7 @@
 			<div class="flex-item-leading">
 				{{ctx.AvatarUtils.AvatarByAction .}}
 			</div>
-			<div class="flex-item-main gt-gap-3">
+			<div class="flex-item-main tw-gap-2">
 				<div>
 					{{if gt .ActUser.ID 0}}
 						<a href="{{AppSubUrl}}/{{(.GetActUserName ctx) | PathEscape}}" title="{{.GetActDisplayNameTitle ctx}}">{{.GetActDisplayName ctx}}</a>
@@ -84,7 +84,7 @@
 					{{$push := ActionContent2Commits .}}
 					{{$repoLink := (.GetRepoLink ctx)}}
 					{{$repo := .Repo}}
-					<div class="gt-df gt-fc gt-gap-2">
+					<div class="tw-flex tw-flex-col tw-gap-1">
 						{{range $push.Commits}}
 							{{$commitLink := printf "%s/commit/%s" $repoLink .Sha1}}
 							<div class="flex-text-block">
@@ -107,7 +107,7 @@
 					<a href="{{.GetCommentLink ctx}}" class="text truncate issue title">{{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}}</a>
 					{{$comment := index .GetIssueInfos 1}}
 					{{if $comment}}
-						<div class="markup gt-font-14">{{RenderMarkdownToHtml ctx $comment}}</div>
+						<div class="markup tw-text-14">{{RenderMarkdownToHtml ctx $comment}}</div>
 					{{end}}
 				{{else if .GetOpType.InActions "merge_pull_request"}}
 					<div class="flex-item-body text black">{{index .GetIssueInfos 1}}</div>
diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl
index 0fbf9a736..5080821dd 100644
--- a/templates/user/dashboard/issues.tmpl
+++ b/templates/user/dashboard/issues.tmpl
@@ -2,32 +2,33 @@
 <div role="main" aria-label="{{.Title}}" class="page-content dashboard issues">
 	{{template "user/dashboard/navbar" .}}
 	<div class="ui container">
+		{{template "base/alert" .}}
 		<div class="flex-container">
 			<div class="flex-container-nav">
 				<div class="ui secondary vertical filter menu tw-bg-transparent">
-					<a class="{{if eq .ViewType "your_repositories"}}active{{end}} item" href="{{.Link}}?type=your_repositories&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
+					<a class="{{if eq .ViewType "your_repositories"}}active{{end}} item" href="?type=your_repositories&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
 						{{ctx.Locale.Tr "home.issues.in_your_repos"}}
 						<strong>{{CountFmt .IssueStats.YourRepositoriesCount}}</strong>
 					</a>
-					<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{.Link}}?type=assigned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
+					<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="?type=assigned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
 						{{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}}
 						<strong>{{CountFmt .IssueStats.AssignCount}}</strong>
 					</a>
-					<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{.Link}}?type=created_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
+					<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="?type=created_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
 						{{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}}
 						<strong>{{CountFmt .IssueStats.CreateCount}}</strong>
 					</a>
 					{{if .PageIsPulls}}
-						<a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="{{.Link}}?type=review_requested&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
+						<a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="?type=review_requested&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
 							{{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}}
 							<strong>{{CountFmt .IssueStats.ReviewRequestedCount}}</strong>
 						</a>
-						<a class="{{if eq .ViewType "reviewed_by"}}active{{end}} item" href="{{.Link}}?type=reviewed_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
+						<a class="{{if eq .ViewType "reviewed_by"}}active{{end}} item" href="?type=reviewed_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
 							{{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}}
 							<strong>{{CountFmt .IssueStats.ReviewedCount}}</strong>
 						</a>
 					{{end}}
-					<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{.Link}}?type=mentioned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
+					<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="?type=mentioned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}">
 						{{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}}
 						<strong>{{CountFmt .IssueStats.MentionCount}}</strong>
 					</a>
@@ -36,11 +37,11 @@
 			<div class="flex-container-main content">
 				<div class="list-header">
 					<div class="small-menu-items ui compact tiny menu list-header-toggle">
-						<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state=open&q={{$.Keyword}}">
+						<a class="item{{if not .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=open&q={{$.Keyword}}">
 							{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
 							{{ctx.Locale.PrettyNumber .IssueStats.OpenCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.open_title"}}
 						</a>
-						<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state=closed&q={{$.Keyword}}">
+						<a class="item{{if .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=closed&q={{$.Keyword}}">
 							{{svg "octicon-issue-closed" 16 "gt-mr-3"}}
 							{{ctx.Locale.PrettyNumber .IssueStats.ClosedCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.closed_title"}}
 						</a>
@@ -62,14 +63,14 @@
 							{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 						</span>
 						<div class="menu">
-							<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
-							<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
-							<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=latest&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
-							<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=oldest&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
-							<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
-							<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
-							<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
-							<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{$.Link}}?type={{$.ViewType}}&sort=farduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
+							<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
+							<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
+							<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="?type={{$.ViewType}}&sort=latest&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
+							<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?type={{$.ViewType}}&sort=oldest&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
+							<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
+							<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
+							<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
+							<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=farduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
 						</div>
 					</div>
 				</div>
diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl
index 7b62c9fc2..3a260c3d1 100644
--- a/templates/user/dashboard/milestones.tmpl
+++ b/templates/user/dashboard/milestones.tmpl
@@ -12,7 +12,7 @@
 					<div class="divider"></div>
 					{{range .Repos}}
 						{{with $Repo := .}}
-							<a class="{{range $.RepoIDs}}{{if eq . $Repo.ID}}active{{end}}{{end}} repo name item" href="{{$.Link}}?repos=[
+							<a class="{{range $.RepoIDs}}{{if eq . $Repo.ID}}active{{end}}{{end}} repo name item" href="?repos=[
 								{{- with $include := true -}}
 										{{- range $.RepoIDs -}}
 											{{- if eq . $Repo.ID -}}
@@ -36,11 +36,11 @@
 			<div class="flex-container-main content">
 				<div class="list-header">
 					<div class="small-menu-items ui compact tiny menu list-header-toggle">
-						<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}">
+						<a class="item{{if not .IsShowClosed}} active{{end}}" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}">
 							{{svg "octicon-milestone" 16 "gt-mr-3"}}
 							{{ctx.Locale.PrettyNumber .MilestoneStats.OpenCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.open_title"}}
 						</a>
-						<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=closed&q={{$.Keyword}}">
+						<a class="item{{if .IsShowClosed}} active{{end}}" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=closed&q={{$.Keyword}}">
 							{{svg "octicon-check" 16 "gt-mr-3"}}
 							{{ctx.Locale.PrettyNumber .MilestoneStats.ClosedCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.closed_title"}}
 						</a>
@@ -59,12 +59,12 @@
 						</span>
 						{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 						<div class="menu">
-							<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.earliest_due_data"}}</a>
-							<a class="{{if eq .SortType "furthestduedate"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.latest_due_date"}}</a>
-							<a class="{{if eq .SortType "leastcomplete"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
-							<a class="{{if eq .SortType "mostcomplete"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
-							<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
-							<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="{{$.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
+							<a class="{{if or (eq .SortType "closestduedate") (not .SortType)}}active {{end}}item" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=closestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.earliest_due_data"}}</a>
+							<a class="{{if eq .SortType "furthestduedate"}}active {{end}}item" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=furthestduedate&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.latest_due_date"}}</a>
+							<a class="{{if eq .SortType "leastcomplete"}}active {{end}}item" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_complete"}}</a>
+							<a class="{{if eq .SortType "mostcomplete"}}active {{end}}item" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostcomplete&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_complete"}}</a>
+							<a class="{{if eq .SortType "mostissues"}}active {{end}}item" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=mostissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.most_issues"}}</a>
+							<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort=leastissues&state={{$.State}}&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
 						</div>
 					</div>
 				</div>
@@ -79,7 +79,7 @@
 									{{svg "octicon-milestone" 16}}
 									<a class="muted" href="{{.Repo.Link}}/milestone/{{.ID}}">{{.Name}}</a>
 								</h3>
-								<div class="gt-df gt-ac">
+								<div class="tw-flex tw-items-center">
 									<span class="gt-mr-3">{{.Completeness}}%</span>
 									<progress value="{{.Completeness}}" max="100"></progress>
 								</div>
diff --git a/templates/user/dashboard/navbar.tmpl b/templates/user/dashboard/navbar.tmpl
index af07897e2..480c39e8b 100644
--- a/templates/user/dashboard/navbar.tmpl
+++ b/templates/user/dashboard/navbar.tmpl
@@ -78,7 +78,7 @@
 
 	{{if .ContextUser.IsOrganization}}
 		<div class="right menu">
-			<a class="{{if .PageIsNews}}active {{end}}item gt-ml-auto" href="{{.ContextUser.DashboardLink}}{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
+			<a class="{{if .PageIsNews}}active {{end}}item tw-ml-auto" href="{{.ContextUser.DashboardLink}}{{if .Team}}/{{PathEscape .Team.Name}}{{end}}">
 				{{svg "octicon-rss"}}&nbsp;{{ctx.Locale.Tr "activities"}}
 			</a>
 			{{if not .UnitIssuesGlobalDisabled}}
@@ -105,4 +105,4 @@
 	{{end}}
 	</div>
 </div>
-<div class="divider"></div>
+<div class="divider tw-mt-0"></div>
diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl
index 431aca097..f0fe6ac6f 100644
--- a/templates/user/notification/notification_div.tmpl
+++ b/templates/user/notification/notification_div.tmpl
@@ -1,7 +1,7 @@
 <div role="main" aria-label="{{.Title}}" class="page-content user notification" id="notification_div" data-sequence-number="{{.SequenceNumber}}">
 	<div class="ui container">
 		{{$notificationUnreadCount := call .NotificationUnreadCount}}
-		<div class="gt-df gt-ac gt-sb gt-mb-4">
+		<div class="tw-flex tw-items-center tw-justify-between gt-mb-4">
 			<div class="small-menu-items ui compact tiny menu">
 				<a class="{{if eq .Status 1}}active {{end}}item" href="{{AppSubUrl}}/notifications?q=unread">
 					{{ctx.Locale.Tr "notification.unread"}}
@@ -25,7 +25,7 @@
 		<div class="gt-p-0">
 			<div id="notification_table">
 				{{if not .Notifications}}
-					<div class="gt-df gt-ac gt-fc gt-p-4">
+					<div class="tw-flex tw-items-center tw-flex-col gt-p-4">
 						{{svg "octicon-inbox" 56 "gt-mb-4"}}
 						{{if eq .Status 1}}
 							{{ctx.Locale.Tr "notification.no_unread"}}
@@ -35,7 +35,7 @@
 					</div>
 				{{else}}
 					{{range $notification := .Notifications}}
-						<div class="notifications-item gt-df gt-ac gt-fw gt-gap-3 gt-p-3" id="notification_{{.ID}}" data-status="{{.Status}}">
+						<div class="notifications-item tw-flex tw-items-center tw-flex-wrap tw-gap-2 gt-p-3" id="notification_{{.ID}}" data-status="{{.Status}}">
 							<div class="notifications-icon gt-ml-3 gt-mr-2 tw-self-start gt-mt-2">
 								{{if .Issue}}
 									{{template "shared/issueicon" .Issue}}
@@ -43,14 +43,14 @@
 									{{svg "octicon-repo" 16 "text grey"}}
 								{{end}}
 							</div>
-							<a class="notifications-link gt-df gt-f1 gt-fc silenced" href="{{.Link ctx}}">
-								<div class="notifications-top-row gt-font-13">
+							<a class="notifications-link tw-flex tw-flex-1 tw-flex-col silenced" href="{{.Link ctx}}">
+								<div class="notifications-top-row tw-text-13">
 									{{.Repository.FullName}} {{if .Issue}}<span class="text light-3">#{{.Issue.Index}}</span>{{end}}
 									{{if eq .Status 3}}
 										{{svg "octicon-pin" 13 "text blue gt-mt-1 gt-ml-2"}}
 									{{end}}
 								</div>
-								<div class="notifications-bottom-row gt-font-16 gt-py-1">
+								<div class="notifications-bottom-row tw-text-16 gt-py-1">
 									<span class="issue-title">
 										{{if .Issue}}
 											{{.Issue.Title | RenderEmoji $.Context | RenderCodeBlock}}
@@ -60,14 +60,14 @@
 									</span>
 								</div>
 							</a>
-							<div class="notifications-updated gt-ac gt-mr-3">
+							<div class="notifications-updated tw-items-center gt-mr-3">
 								{{if .Issue}}
 									{{TimeSinceUnix .Issue.UpdatedUnix ctx.Locale}}
 								{{else}}
 									{{TimeSinceUnix .UpdatedUnix ctx.Locale}}
 								{{end}}
 							</div>
-							<div class="notifications-buttons gt-ac gt-je gt-gap-2 gt-px-2">
+							<div class="notifications-buttons tw-items-center tw-justify-end tw-gap-1 gt-px-2">
 								{{if ne .Status 3}}
 									<form action="{{AppSubUrl}}/notifications/status" method="post">
 										{{$.CsrfTokenHtml}}
diff --git a/templates/user/notification/notification_subscriptions.tmpl b/templates/user/notification/notification_subscriptions.tmpl
index a37f0c352..eb71621d9 100644
--- a/templates/user/notification/notification_subscriptions.tmpl
+++ b/templates/user/notification/notification_subscriptions.tmpl
@@ -11,23 +11,23 @@
 		</div>
 		<div class="ui bottom attached active tab segment">
 			{{if eq .Status 1}}
-				<div class="gt-df gt-sb">
-					<div class="gt-df">
+				<div class="tw-flex tw-justify-between">
+					<div class="tw-flex">
 						<div class="small-menu-items ui compact tiny menu">
-							<a class="{{if eq .State "all"}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state=all&issueType={{$.IssueType}}&labels={{$.Labels}}">
+							<a class="{{if eq .State "all"}}active {{end}}item" href="?sort={{$.SortType}}&state=all&issueType={{$.IssueType}}&labels={{$.Labels}}">
 								{{ctx.Locale.Tr "all"}}
 							</a>
-							<a class="{{if eq .State "open"}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state=open&issueType={{$.IssueType}}&labels={{$.Labels}}">
+							<a class="{{if eq .State "open"}}active {{end}}item" href="?sort={{$.SortType}}&state=open&issueType={{$.IssueType}}&labels={{$.Labels}}">
 								{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
 								{{ctx.Locale.Tr "repo.issues.open_title"}}
 							</a>
-							<a class="{{if eq .State "closed"}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state=closed&issueType={{$.IssueType}}&labels={{$.Labels}}">
+							<a class="{{if eq .State "closed"}}active {{end}}item" href="?sort={{$.SortType}}&state=closed&issueType={{$.IssueType}}&labels={{$.Labels}}">
 								{{svg "octicon-issue-closed" 16 "gt-mr-3"}}
 								{{ctx.Locale.Tr "repo.issues.closed_title"}}
 							</a>
 						</div>
 					</div>
-					<div class="gt-df gt-sb">
+					<div class="tw-flex tw-justify-between">
 						<div class="ui right aligned secondary filter menu labels">
 							<!-- Type -->
 								<div class="ui dropdown type jump item">
@@ -36,9 +36,9 @@
 									</span>
 									{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 									<div class="menu">
-										<a class="{{if or (eq .IssueType "all") (not .IssueType)}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state={{$.State}}&issueType=all&labels={{$.Labels}}">{{ctx.Locale.Tr "all"}}</a>
-										<a class="{{if eq .IssueType "issues"}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state={{$.State}}&issueType=issues&labels={{$.Labels}}">{{ctx.Locale.Tr "issues"}}</a>
-										<a class="{{if eq .IssueType "pulls"}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state={{$.State}}&issueType=pulls&labels={{$.Labels}}">{{ctx.Locale.Tr "pull_requests"}}</a>
+										<a class="{{if or (eq .IssueType "all") (not .IssueType)}}active {{end}}item" href="?sort={{$.SortType}}&state={{$.State}}&issueType=all&labels={{$.Labels}}">{{ctx.Locale.Tr "all"}}</a>
+										<a class="{{if eq .IssueType "issues"}}active {{end}}item" href="?sort={{$.SortType}}&state={{$.State}}&issueType=issues&labels={{$.Labels}}">{{ctx.Locale.Tr "issues"}}</a>
+										<a class="{{if eq .IssueType "pulls"}}active {{end}}item" href="?sort={{$.SortType}}&state={{$.State}}&issueType=pulls&labels={{$.Labels}}">{{ctx.Locale.Tr "pull_requests"}}</a>
 									</div>
 								</div>
 
@@ -49,14 +49,14 @@
 								</span>
 								{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 								<div class="menu">
-									<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="{{$.Link}}?sort=latest&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
-									<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?sort=oldest&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
-									<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
-									<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
-									<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{$.Link}}?sort=mostcomment&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
-									<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{$.Link}}?sort=leastcomment&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
-									<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{$.Link}}?sort=nearduedate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
-									<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{$.Link}}?sort=farduedate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
+									<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="?sort=latest&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
+									<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?sort=oldest&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
+									<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?sort=recentupdate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
+									<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?sort=leastupdate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
+									<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="?sort=mostcomment&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
+									<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="?sort=leastcomment&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
+									<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="?sort=nearduedate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
+									<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="?sort=farduedate&state={{$.State}}&issueType={{$.IssueType}}&labels={{$.Labels}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
 								</div>
 							</div>
 						</div>
diff --git a/templates/user/settings/account.tmpl b/templates/user/settings/account.tmpl
index 29441f97e..63f490991 100644
--- a/templates/user/settings/account.tmpl
+++ b/templates/user/settings/account.tmpl
@@ -46,7 +46,7 @@
 					<form action="{{AppSubUrl}}/user/settings/account/email" class="ui form" method="post">
 						{{$.CsrfTokenHtml}}
 						<input name="_method" type="hidden" value="NOTIFICATION">
-						<div class="gt-df gt-fw gt-gap-3">
+						<div class="tw-flex tw-flex-wrap tw-gap-2">
 							<div class="ui selection dropdown">
 								<input name="preference" type="hidden" value="{{.EmailNotificationsPreference}}">
 								{{svg "octicon-triangle-down" 14 "dropdown icon"}}
@@ -136,7 +136,7 @@
 			<div class="ui red message">
 				<p class="text left">{{svg "octicon-alert"}} {{ctx.Locale.Tr "settings.delete_prompt"}}</p>
 				{{if .UserDeleteWithComments}}
-				<p class="text left gt-font-semibold">{{ctx.Locale.Tr "settings.delete_with_all_comments" .UserDeleteWithCommentsMaxTime}}</p>
+				<p class="text left tw-font-semibold">{{ctx.Locale.Tr "settings.delete_with_all_comments" .UserDeleteWithCommentsMaxTime}}</p>
 				{{end}}
 			</div>
 			<form class="ui form ignore-dirty" id="delete-form" action="{{AppSubUrl}}/user/settings/account/delete" method="post">
diff --git a/templates/user/settings/applications_oauth2_list.tmpl b/templates/user/settings/applications_oauth2_list.tmpl
index bf6b28ec5..bfbebb104 100644
--- a/templates/user/settings/applications_oauth2_list.tmpl
+++ b/templates/user/settings/applications_oauth2_list.tmpl
@@ -4,7 +4,7 @@
 			{{ctx.Locale.Tr "settings.oauth2_application_create_description"}}
 		</div>
 		{{range .Applications}}
-			<div class="flex-item gt-ac">
+			<div class="flex-item tw-items-center">
 				<div class="flex-item-leading">
 					{{svg "octicon-apps" 32}}
 				</div>
diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl
index 2e26d6956..b6bae8951 100644
--- a/templates/user/settings/keys_gpg.tmpl
+++ b/templates/user/settings/keys_gpg.tmpl
@@ -73,7 +73,7 @@
 						{{ctx.Locale.Tr "settings.delete_key"}}
 					</button>
 					{{if and (not .Verified) (ne $.VerifyingID .KeyID)}}
-						<a class="ui primary tiny button" href="{{$.Link}}?verify_gpg={{.KeyID}}">{{ctx.Locale.Tr "settings.gpg_key_verify"}}</a>
+						<a class="ui primary tiny button" href="?verify_gpg={{.KeyID}}">{{ctx.Locale.Tr "settings.gpg_key_verify"}}</a>
 					{{end}}
 				</div>
 			</div>
diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl
index 6aa803a41..5c14d81be 100644
--- a/templates/user/settings/keys_ssh.tmpl
+++ b/templates/user/settings/keys_ssh.tmpl
@@ -61,7 +61,7 @@
 						{{ctx.Locale.Tr "settings.delete_key"}}
 					</button>
 					{{if and (not .Verified) (ne $.VerifyingFingerprint .Fingerprint)}}
-						<a class="ui primary tiny button" href="{{$.Link}}?verify_ssh={{.Fingerprint}}">{{ctx.Locale.Tr "settings.ssh_key_verify"}}</a>
+						<a class="ui primary tiny button" href="?verify_ssh={{.Fingerprint}}">{{ctx.Locale.Tr "settings.ssh_key_verify"}}</a>
 					{{end}}
 				</div>
 			</div>
diff --git a/templates/user/settings/repos.tmpl b/templates/user/settings/repos.tmpl
index eeb2b6cbd..41cdae296 100644
--- a/templates/user/settings/repos.tmpl
+++ b/templates/user/settings/repos.tmpl
@@ -30,8 +30,8 @@
 											<span><a href="{{$repo.BaseRepo.Link}}">{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}</a></span>
 										{{end}}
 									{{else}}
-										<span class="icon gt-dib gt-pt-3">{{svg "octicon-file-directory-fill"}}</span>
-										<span class="name gt-dib gt-pt-3">{{$.ContextUser.Name}}/{{$dir}}</span>
+										<span class="icon tw-inline-block gt-pt-3">{{svg "octicon-file-directory-fill"}}</span>
+										<span class="name tw-inline-block gt-pt-3">{{$.ContextUser.Name}}/{{$dir}}</span>
 										<div class="tw-float-right">
 											{{if $.allowAdopt}}
 												<button class="ui button primary show-modal gt-p-3" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</span></button>
diff --git a/templates/user/settings/security/openid.tmpl b/templates/user/settings/security/openid.tmpl
index 0e9b4adcb..b0473c9df 100644
--- a/templates/user/settings/security/openid.tmpl
+++ b/templates/user/settings/security/openid.tmpl
@@ -7,7 +7,7 @@
 			{{ctx.Locale.Tr "settings.openid_desc"}}
 		</div>
 		{{range .OpenIDs}}
-			<div class="flex-item gt-ac">
+			<div class="flex-item tw-items-center">
 				<div class="flex-item-leading">
 					{{svg "fontawesome-openid" 20}}
 				</div>
diff --git a/templates/webhook/new.tmpl b/templates/webhook/new.tmpl
index 63bd8363b..0347455f2 100644
--- a/templates/webhook/new.tmpl
+++ b/templates/webhook/new.tmpl
@@ -1,7 +1,7 @@
 <h4 class="ui top attached header">
 	{{.CustomHeaderTitle}}
 	<div class="ui right type dropdown">
-		<div class="text gt-df gt-ac">
+		<div class="text tw-flex tw-items-center">
 			{{template "shared/webhook/icon" (dict "Size" 20 "HookType" .ctxData.HookType)}}
 			{{ctx.Locale.Tr (print "repo.settings.web_hook_name_" .ctxData.HookType)}}
 		</div>
diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go
index 0137964a5..9359dc09b 100644
--- a/tests/integration/actions_trigger_test.go
+++ b/tests/integration/actions_trigger_test.go
@@ -11,17 +11,22 @@ import (
 	"time"
 
 	actions_model "code.gitea.io/gitea/models/actions"
+	"code.gitea.io/gitea/models/db"
+	git_model "code.gitea.io/gitea/models/git"
 	issues_model "code.gitea.io/gitea/models/issues"
+	repo_model "code.gitea.io/gitea/models/repo"
 	unit_model "code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/models/unittest"
 	user_model "code.gitea.io/gitea/models/user"
 	actions_module "code.gitea.io/gitea/modules/actions"
 	"code.gitea.io/gitea/modules/git"
+	"code.gitea.io/gitea/modules/gitrepo"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/test"
 	webhook_module "code.gitea.io/gitea/modules/webhook"
 	actions_service "code.gitea.io/gitea/services/actions"
 	pull_service "code.gitea.io/gitea/services/pull"
+	release_service "code.gitea.io/gitea/services/release"
 	repo_service "code.gitea.io/gitea/services/repository"
 	files_service "code.gitea.io/gitea/services/repository/files"
 
@@ -275,3 +280,119 @@ func TestSkipCI(t *testing.T) {
 		assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
 	})
 }
+
+func TestCreateDeleteRefEvent(t *testing.T) {
+	onGiteaRun(t, func(t *testing.T, u *url.URL) {
+		user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+
+		// create the repo
+		repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+			Name:          "create-delete-ref-event",
+			Description:   "test create delete ref ci event",
+			AutoInit:      true,
+			Gitignores:    "Go",
+			License:       "MIT",
+			Readme:        "Default",
+			DefaultBranch: "main",
+			IsPrivate:     false,
+		})
+		assert.NoError(t, err)
+		assert.NotEmpty(t, repo)
+
+		// enable actions
+		err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{
+			RepoID: repo.ID,
+			Type:   unit_model.TypeActions,
+		}}, nil)
+		assert.NoError(t, err)
+
+		// add workflow file to the repo
+		addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+			Files: []*files_service.ChangeRepoFile{
+				{
+					Operation:     "create",
+					TreePath:      ".gitea/workflows/createdelete.yml",
+					ContentReader: strings.NewReader("name: test\non:\n  [create,delete]\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - run: echo helloworld\n"),
+				},
+			},
+			Message:   "add workflow",
+			OldBranch: "main",
+			NewBranch: "main",
+			Author: &files_service.IdentityOptions{
+				Name:  user2.Name,
+				Email: user2.Email,
+			},
+			Committer: &files_service.IdentityOptions{
+				Name:  user2.Name,
+				Email: user2.Email,
+			},
+			Dates: &files_service.CommitDateOptions{
+				Author:    time.Now(),
+				Committer: time.Now(),
+			},
+		})
+		assert.NoError(t, err)
+		assert.NotEmpty(t, addWorkflowToBaseResp)
+
+		// Get the commit ID of the default branch
+		gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+		assert.NoError(t, err)
+		defer gitRepo.Close()
+		branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+		assert.NoError(t, err)
+
+		// create a branch
+		err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-create-branch")
+		assert.NoError(t, err)
+		run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+			Title:      "add workflow",
+			RepoID:     repo.ID,
+			Event:      "create",
+			Ref:        "refs/heads/test-create-branch",
+			WorkflowID: "createdelete.yml",
+			CommitSHA:  branch.CommitID,
+		})
+		assert.NotNil(t, run)
+
+		// create a tag
+		err = release_service.CreateNewTag(db.DefaultContext, user2, repo, branch.CommitID, "test-create-tag", "test create tag event")
+		assert.NoError(t, err)
+		run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+			Title:      "add workflow",
+			RepoID:     repo.ID,
+			Event:      "create",
+			Ref:        "refs/tags/test-create-tag",
+			WorkflowID: "createdelete.yml",
+			CommitSHA:  branch.CommitID,
+		})
+		assert.NotNil(t, run)
+
+		// delete the branch
+		err = repo_service.DeleteBranch(db.DefaultContext, user2, repo, gitRepo, "test-create-branch")
+		assert.NoError(t, err)
+		run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+			Title:      "add workflow",
+			RepoID:     repo.ID,
+			Event:      "delete",
+			Ref:        "main",
+			WorkflowID: "createdelete.yml",
+			CommitSHA:  branch.CommitID,
+		})
+		assert.NotNil(t, run)
+
+		// delete the tag
+		tag, err := repo_model.GetRelease(db.DefaultContext, repo.ID, "test-create-tag")
+		assert.NoError(t, err)
+		err = release_service.DeleteReleaseByID(db.DefaultContext, repo, tag, user2, true)
+		assert.NoError(t, err)
+		run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+			Title:      "add workflow",
+			RepoID:     repo.ID,
+			Event:      "delete",
+			Ref:        "main",
+			WorkflowID: "createdelete.yml",
+			CommitSHA:  branch.CommitID,
+		})
+		assert.NotNil(t, run)
+	})
+}
diff --git a/tests/integration/explore_user_test.go b/tests/integration/explore_user_test.go
index 046caf378..441d89cea 100644
--- a/tests/integration/explore_user_test.go
+++ b/tests/integration/explore_user_test.go
@@ -16,17 +16,17 @@ func TestExploreUser(t *testing.T) {
 	defer tests.PrepareTestEnv(t)()
 
 	cases := []struct{ sortOrder, expected string }{
-		{"", "/explore/users?sort=newest&q="},
-		{"newest", "/explore/users?sort=newest&q="},
-		{"oldest", "/explore/users?sort=oldest&q="},
-		{"alphabetically", "/explore/users?sort=alphabetically&q="},
-		{"reversealphabetically", "/explore/users?sort=reversealphabetically&q="},
+		{"", "?sort=newest&q="},
+		{"newest", "?sort=newest&q="},
+		{"oldest", "?sort=oldest&q="},
+		{"alphabetically", "?sort=alphabetically&q="},
+		{"reversealphabetically", "?sort=reversealphabetically&q="},
 	}
 	for _, c := range cases {
 		req := NewRequest(t, "GET", "/explore/users?sort="+c.sortOrder)
 		resp := MakeRequest(t, req, http.StatusOK)
 		h := NewHTMLParser(t, resp.Body)
-		href, _ := h.Find(`.ui.dropdown .menu a.active.item[href^="/explore/users"]`).Attr("href")
+		href, _ := h.Find(`.ui.dropdown .menu a.active.item[href^="?sort="]`).Attr("href")
 		assert.Equal(t, c.expected, href)
 	}
 
diff --git a/tests/integration/git_push_test.go b/tests/integration/git_push_test.go
index cb2910b17..0a3572480 100644
--- a/tests/integration/git_push_test.go
+++ b/tests/integration/git_push_test.go
@@ -69,6 +69,23 @@ func testGitPush(t *testing.T, u *url.URL) {
 			return pushed, deleted
 		})
 	})
+
+	t.Run("Push to deleted branch", func(t *testing.T) {
+		runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
+			doGitPushTestRepository(gitPath, "origin", "master")(t) // make sure master is the default branch instead of a branch we are going to delete
+			pushed = append(pushed, "master")
+
+			doGitCreateBranch(gitPath, "branch-1")(t)
+			doGitPushTestRepository(gitPath, "origin", "branch-1")(t)
+			pushed = append(pushed, "branch-1")
+
+			// delete and restore
+			doGitPushTestRepository(gitPath, "origin", "--delete", "branch-1")(t)
+			doGitPushTestRepository(gitPath, "origin", "branch-1")(t)
+
+			return pushed, deleted
+		})
+	})
 }
 
 func runTestGitPush(t *testing.T, u *url.URL, gitOperation func(t *testing.T, gitPath string) (pushed, deleted []string)) {
diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go
index 6c1da4f4a..38c3a091b 100644
--- a/tests/integration/issue_test.go
+++ b/tests/integration/issue_test.go
@@ -807,7 +807,7 @@ func TestIssueFilterNoFollow(t *testing.T) {
 	htmlDoc := NewHTMLParser(t, resp.Body)
 
 	// Check that every link in the filter list has rel="nofollow".
-	filterLinks := htmlDoc.Find(".issue-list-toolbar-right a[href*=\"/issues?q=\"]")
+	filterLinks := htmlDoc.Find(".issue-list-toolbar-right a[href*=\"?q=\"]")
 	assert.True(t, filterLinks.Length() > 0)
 	filterLinks.Each(func(i int, link *goquery.Selection) {
 		rel, has := link.Attr("rel")
diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go
index e79d99b05..c9ecadca9 100644
--- a/tests/integration/pull_merge_test.go
+++ b/tests/integration/pull_merge_test.go
@@ -513,8 +513,8 @@ func TestConflictChecking(t *testing.T) {
 		assert.NoError(t, err)
 
 		issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "PR with conflict!"})
-		conflictingPR, err := issues_model.GetPullRequestByIssueID(db.DefaultContext, issue.ID)
-		assert.NoError(t, err)
+		assert.NoError(t, issue.LoadPullRequest(db.DefaultContext))
+		conflictingPR := issue.PullRequest
 
 		// Ensure conflictedFiles is populated.
 		assert.Len(t, conflictingPR.ConflictedFiles, 1)
diff --git a/tests/integration/pull_update_test.go b/tests/integration/pull_update_test.go
index 094813d36..d59d2641f 100644
--- a/tests/integration/pull_update_test.go
+++ b/tests/integration/pull_update_test.go
@@ -167,8 +167,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
 	assert.NoError(t, err)
 
 	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "Test Pull -to-update-"})
-	pr, err := issues_model.GetPullRequestByIssueID(db.DefaultContext, issue.ID)
-	assert.NoError(t, err)
+	assert.NoError(t, issue.LoadPullRequest(db.DefaultContext))
 
-	return pr
+	return issue.PullRequest
 }
diff --git a/tests/integration/release_test.go b/tests/integration/release_test.go
index 3ae2703af..acc8cb68c 100644
--- a/tests/integration/release_test.go
+++ b/tests/integration/release_test.go
@@ -285,7 +285,7 @@ func TestViewTagsList(t *testing.T) {
 
 	tagNames := make([]string, 0, 5)
 	tags.Each(func(i int, s *goquery.Selection) {
-		tagNames = append(tagNames, s.Find(".tag a.gt-df.gt-ac").Text())
+		tagNames = append(tagNames, s.Find(".tag a.tw-flex.tw-items-center").Text())
 	})
 
 	assert.EqualValues(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames)
diff --git a/tests/integration/repo_search_test.go b/tests/integration/repo_search_test.go
index e5ee334ce..aecf75025 100644
--- a/tests/integration/repo_search_test.go
+++ b/tests/integration/repo_search_test.go
@@ -46,7 +46,7 @@ func testSearchRepo(t *testing.T, useExternalIndexer bool) {
 
 	if useExternalIndexer {
 		gitReference = "/commit/"
-		executeIndexer(t, repo, code_indexer.UpdateRepoIndexer)
+		code_indexer.UpdateRepoIndexer(repo)
 	}
 
 	testSearch(t, "/user2/repo1/search?q=Description&page=1", gitReference, []string{"README.md"})
@@ -58,12 +58,14 @@ func testSearchRepo(t *testing.T, useExternalIndexer bool) {
 		repo, err = repo_model.GetRepositoryByOwnerAndName(db.DefaultContext, "user2", "glob")
 		assert.NoError(t, err)
 
-		executeIndexer(t, repo, code_indexer.UpdateRepoIndexer)
+		code_indexer.UpdateRepoIndexer(repo)
 
 		testSearch(t, "/user2/glob/search?q=loren&page=1", gitReference, []string{"a.txt"})
-		testSearch(t, "/user2/glob/search?q=file3&page=1", gitReference, []string{"x/b.txt"})
-		testSearch(t, "/user2/glob/search?q=file4&page=1", gitReference, []string{})
-		testSearch(t, "/user2/glob/search?q=file5&page=1", gitReference, []string{})
+		testSearch(t, "/user2/glob/search?q=loren&page=1&t=match", gitReference, []string{"a.txt"})
+		testSearch(t, "/user2/glob/search?q=file3&page=1", gitReference, []string{"x/b.txt", "a.txt"})
+		testSearch(t, "/user2/glob/search?q=file3&page=1&t=match", gitReference, []string{"x/b.txt", "a.txt"})
+		testSearch(t, "/user2/glob/search?q=file4&page=1&t=match", gitReference, []string{"x/b.txt", "a.txt"})
+		testSearch(t, "/user2/glob/search?q=file5&page=1&t=match", gitReference, []string{"x/b.txt", "a.txt"})
 	}
 }
 
@@ -88,7 +90,3 @@ func testSearch(t *testing.T, url, gitRef string, expected []string) {
 
 	checkResultLinks(t, gitRef, doc)
 }
-
-func executeIndexer(t *testing.T, repo *repo_model.Repository, op func(*repo_model.Repository)) {
-	op(repo)
-}
diff --git a/build/generate-images.js b/tools/generate-images.js
similarity index 92%
rename from build/generate-images.js
rename to tools/generate-images.js
index db31d19e2..0bd3af29e 100755
--- a/build/generate-images.js
+++ b/tools/generate-images.js
@@ -1,7 +1,7 @@
 #!/usr/bin/env node
-import imageminZopfli from 'imagemin-zopfli';
+import imageminZopfli from 'imagemin-zopfli'; // eslint-disable-line i/no-unresolved
+import {loadSVGFromString, Canvas, Rect, util} from 'fabric/node'; // eslint-disable-line i/no-unresolved
 import {optimize} from 'svgo';
-import {loadSVGFromString, Canvas, Rect, util} from 'fabric/node';
 import {readFile, writeFile} from 'node:fs/promises';
 import {argv, exit} from 'node:process';
 
@@ -20,7 +20,7 @@ async function generate(svg, path, {size, bg}) {
         'removeDimensions',
         {
           name: 'addAttributesToSVGElement',
-          params: {attributes: [{width: size}, {height: size}]}
+          params: {attributes: [{width: size}, {height: size}]},
         },
       ],
     });
diff --git a/build/generate-svg.js b/tools/generate-svg.js
similarity index 98%
rename from build/generate-svg.js
rename to tools/generate-svg.js
index 660ac9157..1c5851e7e 100755
--- a/build/generate-svg.js
+++ b/tools/generate-svg.js
@@ -39,8 +39,8 @@ async function processFile(file, {prefix, fullName} = {}) {
           attributes: [
             {'xmlns': 'http://www.w3.org/2000/svg'},
             {'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'},
-          ]
-        }
+          ],
+        },
       },
     ],
   });
diff --git a/build/watch.sh b/tools/watch.sh
similarity index 100%
rename from build/watch.sh
rename to tools/watch.sh
diff --git a/vitest.config.js b/vitest.config.js
index be6c0eadf..ea0fafeee 100644
--- a/vitest.config.js
+++ b/vitest.config.js
@@ -6,7 +6,7 @@ export default defineConfig({
   test: {
     include: ['web_src/**/*.test.js'],
     setupFiles: ['web_src/js/vitest.setup.js'],
-    environment: 'jsdom',
+    environment: 'happy-dom',
     testTimeout: 20000,
     open: false,
     allowOnly: true,
diff --git a/web_src/css/actions.css b/web_src/css/actions.css
index e353a013a..e7b9a3855 100644
--- a/web_src/css/actions.css
+++ b/web_src/css/actions.css
@@ -14,10 +14,6 @@
   color: var(--color-red-light);
 }
 
-.runner-container .runner-basic-info .gt-dib {
-  margin-right: 1em;
-}
-
 .runner-container .runner-new-text {
   color: var(--color-white);
 }
diff --git a/web_src/css/base.css b/web_src/css/base.css
index 5a9c93852..e0c43442a 100644
--- a/web_src/css/base.css
+++ b/web_src/css/base.css
@@ -37,6 +37,23 @@
   border-color: currentcolor;
 }
 
+html, body {
+  height: 100%;
+  font-size: 14px;
+}
+
+body {
+  line-height: 1.4285rem;
+  font-family: var(--fonts-regular);
+  color: var(--color-text);
+  background-color: var(--color-body);
+  tab-size: var(--tab-size);
+  display: flex;
+  flex-direction: column;
+  overflow-x: visible;
+  overflow-wrap: break-word;
+}
+
 textarea {
   font-family: var(--fonts-regular);
 }
@@ -60,13 +77,65 @@ h6 {
   font-weight: var(--font-weight-semibold);
 }
 
-body {
-  color: var(--color-text);
-  background-color: var(--color-body);
-  tab-size: var(--tab-size);
-  display: flex;
-  flex-direction: column;
-  overflow-wrap: break-word;
+h1,
+h2,
+h3,
+h4,
+h5 {
+  line-height: 1.28571429;
+  margin: calc(2rem - 0.1428571428571429em) 0 1rem;
+  font-weight: var(--font-weight-medium);
+  padding: 0;
+}
+
+h1 {
+  min-height: 1rem;
+  font-size: 2rem;
+}
+
+h2 {
+  font-size: 1.71428571rem;
+}
+
+h3 {
+  font-size: 1.28571429rem;
+}
+
+h4 {
+  font-size: 1.07142857rem;
+}
+
+h5 {
+  font-size: 1rem;
+}
+
+h1:first-child,
+h2:first-child,
+h3:first-child,
+h4:first-child,
+h5:first-child {
+  margin-top: 0;
+}
+
+h1:last-child,
+h2:last-child,
+h3:last-child,
+h4:last-child,
+h5:last-child {
+  margin-bottom: 0;
+}
+
+p {
+  margin: 0 0 1em;
+  line-height: 1.4285;
+}
+
+p:first-child {
+  margin-top: 0;
+}
+
+p:last-child {
+  margin-bottom: 0;
 }
 
 table {
@@ -132,8 +201,8 @@ h1.error-code {
 }
 
 ::selection {
-  background: var(--color-primary-light-1) !important;
-  color: var(--color-white) !important;
+  background: var(--color-primary-light-1);
+  color: var(--color-white);
 }
 
 ::placeholder,
@@ -157,6 +226,7 @@ h1.error-code {
 a {
   color: var(--color-primary);
   cursor: pointer;
+  text-decoration: none;
   text-decoration-skip-ink: all;
 }
 
@@ -238,16 +308,6 @@ a.label,
   border-bottom-color: var(--color-secondary);
 }
 
-.page-content {
-  margin-top: 15px;
-}
-
-.page-content .header-wrapper,
-.page-content overflow-menu {
-  margin-top: -15px !important;
-  padding-top: 15px !important;
-}
-
 /* fix Fomantic's line-height cutting off "g" on Windows Chrome with Segoe UI */
 .ui.input > input {
   line-height: var(--line-height-default);
@@ -294,7 +354,9 @@ ol.ui.list li,
 .ui.action.input:not([class*="left action"]) > input:focus + .ui.dropdown.selection,
 .ui.action.input:not([class*="left action"]) > input:focus + .ui.dropdown.selection:hover,
 .ui.action.input:not([class*="left action"]) > input:focus + .button,
-.ui.action.input:not([class*="left action"]) > input:focus + .button:hover {
+.ui.action.input:not([class*="left action"]) > input:focus + .button:hover,
+.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button,
+.ui.action.input:not([class*="left action"]) > input:focus + .icon + .button:hover {
   border-left-color: var(--color-primary);
 }
 .ui.action.input:not([class*="left action"]) > input:focus {
@@ -687,6 +749,11 @@ img.ui.avatar,
   padding-bottom: 80px;
 }
 
+.page-content.new:is(.repo,.migrate,.org),
+.page-content.profile:is(.user,.organization) {
+  padding-top: 15px;
+}
+
 /* overwrite semantic width of containers inside the main page content div (div with class "page-content") */
 .page-content .ui.ui.ui.container:not(.fluid) {
   width: 1280px;
@@ -723,16 +790,6 @@ img.ui.avatar,
   background: var(--color-active);
 }
 
-.ui.loading.segment::before,
-.ui.loading.form::before {
-  background: none;
-}
-
-.ui.loading.form > *,
-.ui.loading.segment > * {
-  opacity: 0.35;
-}
-
 .ui.form .fields.error .field textarea,
 .ui.form .fields.error .field select,
 .ui.form .fields.error .field input:not([type]),
@@ -824,10 +881,6 @@ input:-webkit-autofill:active,
   opacity: var(--opacity-disabled);
 }
 
-.ui.loading.loading.input > i.icon svg {
-  visibility: hidden;
-}
-
 .text.primary {
   color: var(--color-primary) !important;
 }
@@ -1972,6 +2025,10 @@ table th[data-sortt-desc] .svg {
   justify-content: center;
 }
 
+.ui.icon.input > i.icon {
+  transition: none;
+}
+
 .flex-items-block > .item,
 .flex-text-block {
   display: flex;
diff --git a/web_src/css/dashboard.css b/web_src/css/dashboard.css
index 57ddb80bc..6271a99c2 100644
--- a/web_src/css/dashboard.css
+++ b/web_src/css/dashboard.css
@@ -78,8 +78,7 @@
 }
 
 .dashboard .dashboard-navbar {
-  padding-left: 0.5rem;
-  padding-right: 0.5rem;
+  padding: 4px 12px;
 }
 
 .dashboard .dashboard-navbar .right.menu {
diff --git a/web_src/css/features/gitgraph.css b/web_src/css/features/gitgraph.css
index 795e1f2d6..6a04c44e5 100644
--- a/web_src/css/features/gitgraph.css
+++ b/web_src/css/features/gitgraph.css
@@ -4,12 +4,6 @@
   min-height: 350px;
 }
 
-#git-graph-container > .ui.segment.loading {
-  border: 0;
-  z-index: 1;
-  min-height: 246px;
-}
-
 #git-graph-container h2 {
   display: flex;
   justify-content: space-between;
diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css
index 860722823..b7742b5cf 100644
--- a/web_src/css/helpers.css
+++ b/web_src/css/helpers.css
@@ -2,16 +2,6 @@
 Gitea's tailwind-style CSS helper classes have `gt-` prefix.
 Gitea's private styles use `g-` prefix.
 */
-.gt-df { display: flex !important; }
-.gt-dib { display: inline-block !important; }
-.gt-ac { align-items: center !important; }
-.gt-jc { justify-content: center !important; }
-.gt-je { justify-content: flex-end !important; }
-.gt-sb { justify-content: space-between !important; }
-.gt-fc { flex-direction: column !important; }
-.gt-f1 { flex: 1 !important; }
-.gt-fw { flex-wrap: wrap !important; }
-.gt-vm { vertical-align: middle !important; }
 
 .gt-mono {
   font-family: var(--fonts-monospace) !important;
@@ -46,24 +36,6 @@ Gitea's private styles use `g-` prefix.
   text-overflow: ellipsis;
 }
 
-.gt-font-light { font-weight: var(--font-weight-light) !important; }
-.gt-font-normal { font-weight: var(--font-weight-normal) !important; }
-.gt-font-medium { font-weight: var(--font-weight-medium) !important; }
-.gt-font-semibold { font-weight: var(--font-weight-semibold) !important; }
-.gt-font-bold { font-weight: var(--font-weight-bold) !important; }
-
-.gt-rounded { border-radius: var(--border-radius) !important; }
-.gt-rounded-top { border-radius: var(--border-radius) var(--border-radius) 0 0 !important; }
-.gt-rounded-bottom { border-radius: 0 0 var(--border-radius) var(--border-radius) !important; }
-.gt-rounded-left { border-radius: var(--border-radius) 0 0 var(--border-radius) !important; }
-.gt-rounded-right { border-radius: 0 var(--border-radius) var(--border-radius) 0 !important; }
-
-.gt-border-secondary { border: 1px solid var(--color-secondary) !important; }
-.gt-border-secondary-top { border-top: 1px solid var(--color-secondary) !important; }
-.gt-border-secondary-bottom { border-bottom: 1px solid var(--color-secondary) !important; }
-.gt-border-secondary-left { border-left: 1px solid var(--color-secondary) !important; }
-.gt-border-secondary-right { border-right: 1px solid var(--color-secondary) !important; }
-
 .interact-fg { color: inherit !important; }
 .interact-fg:hover { color: var(--color-primary) !important; }
 .interact-fg:active { color: var(--color-primary-active) !important; }
@@ -121,14 +93,6 @@ Gitea's private styles use `g-` prefix.
 .gt-my-4 { margin-top: 1rem !important; margin-bottom: 1rem !important; }
 .gt-my-5 { margin-top: 2rem !important; margin-bottom: 2rem !important; }
 
-.gt-m-auto  { margin: auto !important; }
-.gt-mx-auto { margin-left: auto !important; margin-right: auto !important; }
-.gt-my-auto { margin-top: auto !important; margin-bottom: auto !important; }
-.gt-mt-auto { margin-top: auto !important; }
-.gt-mr-auto { margin-right: auto !important; }
-.gt-mb-auto { margin-bottom: auto !important; }
-.gt-ml-auto { margin-left: auto !important; }
-
 .gt-p-0 { padding: 0 !important; }
 .gt-p-1 { padding: .125rem !important; }
 .gt-p-2 { padding: .25rem !important; }
@@ -178,37 +142,6 @@ Gitea's private styles use `g-` prefix.
 .gt-py-4 { padding-top: 1rem !important; padding-bottom: 1rem !important; }
 .gt-py-5 { padding-top: 2rem !important; padding-bottom: 2rem !important; }
 
-.gt-gap-0 { gap: 0 !important; }
-.gt-gap-1 { gap: .125rem !important; }
-.gt-gap-2 { gap: .25rem !important; }
-.gt-gap-3 { gap: .5rem !important; }
-.gt-gap-4 { gap: 1rem !important; }
-.gt-gap-5 { gap: 2rem !important; }
-
-.gt-gap-x-0 { column-gap: 0 !important; }
-.gt-gap-x-1 { column-gap: .125rem !important; }
-.gt-gap-x-2 { column-gap: .25rem !important; }
-.gt-gap-x-3 { column-gap: .5rem !important; }
-.gt-gap-x-4 { column-gap: 1rem !important; }
-.gt-gap-x-5 { column-gap: 2rem !important; }
-
-.gt-gap-y-0 { row-gap: 0 !important; }
-.gt-gap-y-1 { row-gap: .125rem !important; }
-.gt-gap-y-2 { row-gap: .25rem !important; }
-.gt-gap-y-3 { row-gap: .5rem !important; }
-.gt-gap-y-4 { row-gap: 1rem !important; }
-.gt-gap-y-5 { row-gap: 2rem !important; }
-
-.gt-shrink-0 { flex-shrink: 0 !important; }
-
-.gt-font-12 { font-size: 12px !important }
-.gt-font-13 { font-size: 13px !important }
-.gt-font-14 { font-size: 14px !important }
-.gt-font-15 { font-size: 15px !important }
-.gt-font-16 { font-size: 16px !important }
-.gt-font-17 { font-size: 17px !important }
-.gt-font-18 { font-size: 18px !important }
-
 /*
 gt-hidden must win all other "display: xxx !important" classes to get the chance to "hide" an element.
 do not use:
diff --git a/web_src/css/index.css b/web_src/css/index.css
index f6e4c196e..bf568bff4 100644
--- a/web_src/css/index.css
+++ b/web_src/css/index.css
@@ -1,5 +1,6 @@
 @import "./modules/normalize.css";
 @import "./modules/animations.css";
+@import "./modules/grid.css";
 @import "./modules/button.css";
 @import "./modules/select.css";
 @import "./modules/tippy.css";
diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css
index 3c80eb99c..a06cab446 100644
--- a/web_src/css/modules/button.css
+++ b/web_src/css/modules/button.css
@@ -154,7 +154,7 @@ It needs some tricks to tweak the left/right borders with active state */
 }
 
 .ui.basic.primary.buttons .button,
-.ui.basic.primary.button{
+.ui.basic.primary.button {
   color: var(--color-primary);
   border-color: var(--color-primary);
 }
diff --git a/web_src/css/modules/grid.css b/web_src/css/modules/grid.css
new file mode 100644
index 000000000..5a80576c8
--- /dev/null
+++ b/web_src/css/modules/grid.css
@@ -0,0 +1,498 @@
+/* based on Fomantic UI grid module, with just the parts extracted that we use. If you find any
+   unused rules here after refactoring, please remove them. */
+
+.ui.grid {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  align-items: stretch;
+  padding: 0;
+  margin-top: -1rem;
+  margin-bottom: -1rem;
+  margin-left: -1rem;
+  margin-right: -1rem;
+}
+
+.ui.relaxed.grid {
+  margin-left: -1.5rem;
+  margin-right: -1.5rem;
+}
+.ui[class*="very relaxed"].grid {
+  margin-left: -2.5rem;
+  margin-right: -2.5rem;
+}
+
+.ui.grid + .grid {
+  margin-top: 1rem;
+}
+
+.ui.grid > .column:not(.row),
+.ui.grid > .row > .column {
+  position: relative;
+  display: inline-block;
+  width: 6.25%;
+  padding-left: 1rem;
+  padding-right: 1rem;
+  vertical-align: top;
+}
+.ui.grid > * {
+  padding-left: 1rem;
+  padding-right: 1rem;
+}
+
+.ui.grid > .row {
+  position: relative;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  justify-content: inherit;
+  align-items: stretch;
+  width: 100% !important;
+  padding: 0;
+  padding-top: 1rem;
+  padding-bottom: 1rem;
+}
+
+.ui.grid > .column:not(.row) {
+  padding-top: 1rem;
+  padding-bottom: 1rem;
+}
+.ui.grid > .row > .column {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+.ui.grid > .row > img,
+.ui.grid > .row > .column > img {
+  max-width: 100%;
+}
+
+.ui.grid > .ui.grid:first-child {
+  margin-top: 0;
+}
+.ui.grid > .ui.grid:last-child {
+  margin-bottom: 0;
+}
+
+.ui.grid .aligned.row > .column > .segment:not(.compact):not(.attached),
+.ui.aligned.grid .column > .segment:not(.compact):not(.attached) {
+  width: 100%;
+}
+
+.ui.grid .row + .ui.divider {
+  flex-grow: 1;
+  margin: 1rem;
+}
+.ui.grid .column + .ui.vertical.divider {
+  height: calc(50% - 1rem);
+}
+
+.ui.grid > .row > .column:last-child > .horizontal.segment,
+.ui.grid > .column:last-child > .horizontal.segment {
+  box-shadow: none;
+}
+
+@media only screen and (max-width: 767.98px) {
+  .ui.page.grid {
+    width: auto;
+    padding-left: 0;
+    padding-right: 0;
+    margin-left: 0;
+    margin-right: 0;
+  }
+}
+@media only screen and (min-width: 768px) and (max-width: 991.98px) {
+  .ui.page.grid {
+    width: auto;
+    margin-left: 0;
+    margin-right: 0;
+    padding-left: 2em;
+    padding-right: 2em;
+  }
+}
+@media only screen and (min-width: 992px) and (max-width: 1199.98px) {
+  .ui.page.grid {
+    width: auto;
+    margin-left: 0;
+    margin-right: 0;
+    padding-left: 3%;
+    padding-right: 3%;
+  }
+}
+@media only screen and (min-width: 1200px) and (max-width: 1919.98px) {
+  .ui.page.grid {
+    width: auto;
+    margin-left: 0;
+    margin-right: 0;
+    padding-left: 15%;
+    padding-right: 15%;
+  }
+}
+@media only screen and (min-width: 1920px) {
+  .ui.page.grid {
+    width: auto;
+    margin-left: 0;
+    margin-right: 0;
+    padding-left: 23%;
+    padding-right: 23%;
+  }
+}
+
+.ui.grid > .column:only-child,
+.ui.grid > .row > .column:only-child {
+  width: 100%;
+}
+
+.ui[class*="one column"].grid > .row > .column,
+.ui[class*="one column"].grid > .column:not(.row) {
+  width: 100%;
+}
+.ui[class*="two column"].grid > .row > .column,
+.ui[class*="two column"].grid > .column:not(.row) {
+  width: 50%;
+}
+.ui[class*="three column"].grid > .row > .column,
+.ui[class*="three column"].grid > .column:not(.row) {
+  width: 33.33333333%;
+}
+.ui[class*="four column"].grid > .row > .column,
+.ui[class*="four column"].grid > .column:not(.row) {
+  width: 25%;
+}
+.ui[class*="five column"].grid > .row > .column,
+.ui[class*="five column"].grid > .column:not(.row) {
+  width: 20%;
+}
+.ui[class*="six column"].grid > .row > .column,
+.ui[class*="six column"].grid > .column:not(.row) {
+  width: 16.66666667%;
+}
+.ui[class*="seven column"].grid > .row > .column,
+.ui[class*="seven column"].grid > .column:not(.row) {
+  width: 14.28571429%;
+}
+.ui[class*="eight column"].grid > .row > .column,
+.ui[class*="eight column"].grid > .column:not(.row) {
+  width: 12.5%;
+}
+.ui[class*="nine column"].grid > .row > .column,
+.ui[class*="nine column"].grid > .column:not(.row) {
+  width: 11.11111111%;
+}
+.ui[class*="ten column"].grid > .row > .column,
+.ui[class*="ten column"].grid > .column:not(.row) {
+  width: 10%;
+}
+.ui[class*="eleven column"].grid > .row > .column,
+.ui[class*="eleven column"].grid > .column:not(.row) {
+  width: 9.09090909%;
+}
+.ui[class*="twelve column"].grid > .row > .column,
+.ui[class*="twelve column"].grid > .column:not(.row) {
+  width: 8.33333333%;
+}
+.ui[class*="thirteen column"].grid > .row > .column,
+.ui[class*="thirteen column"].grid > .column:not(.row) {
+  width: 7.69230769%;
+}
+.ui[class*="fourteen column"].grid > .row > .column,
+.ui[class*="fourteen column"].grid > .column:not(.row) {
+  width: 7.14285714%;
+}
+.ui[class*="fifteen column"].grid > .row > .column,
+.ui[class*="fifteen column"].grid > .column:not(.row) {
+  width: 6.66666667%;
+}
+.ui[class*="sixteen column"].grid > .row > .column,
+.ui[class*="sixteen column"].grid > .column:not(.row) {
+  width: 6.25%;
+}
+
+.ui.grid > [class*="one column"].row > .column {
+  width: 100% !important;
+}
+.ui.grid > [class*="two column"].row > .column {
+  width: 50% !important;
+}
+.ui.grid > [class*="three column"].row > .column {
+  width: 33.33333333% !important;
+}
+.ui.grid > [class*="four column"].row > .column {
+  width: 25% !important;
+}
+.ui.grid > [class*="five column"].row > .column {
+  width: 20% !important;
+}
+.ui.grid > [class*="six column"].row > .column {
+  width: 16.66666667% !important;
+}
+.ui.grid > [class*="seven column"].row > .column {
+  width: 14.28571429% !important;
+}
+.ui.grid > [class*="eight column"].row > .column {
+  width: 12.5% !important;
+}
+.ui.grid > [class*="nine column"].row > .column {
+  width: 11.11111111% !important;
+}
+.ui.grid > [class*="ten column"].row > .column {
+  width: 10% !important;
+}
+.ui.grid > [class*="eleven column"].row > .column {
+  width: 9.09090909% !important;
+}
+.ui.grid > [class*="twelve column"].row > .column {
+  width: 8.33333333% !important;
+}
+.ui.grid > [class*="thirteen column"].row > .column {
+  width: 7.69230769% !important;
+}
+.ui.grid > [class*="fourteen column"].row > .column {
+  width: 7.14285714% !important;
+}
+.ui.grid > [class*="fifteen column"].row > .column {
+  width: 6.66666667% !important;
+}
+.ui.grid > [class*="sixteen column"].row > .column {
+  width: 6.25% !important;
+}
+
+.ui.grid > .row > [class*="one wide"].column,
+.ui.grid > .column.row > [class*="one wide"].column,
+.ui.grid > [class*="one wide"].column,
+.ui.column.grid > [class*="one wide"].column {
+  width: 6.25% !important;
+}
+.ui.grid > .row > [class*="two wide"].column,
+.ui.grid > .column.row > [class*="two wide"].column,
+.ui.grid > [class*="two wide"].column,
+.ui.column.grid > [class*="two wide"].column {
+  width: 12.5% !important;
+}
+.ui.grid > .row > [class*="three wide"].column,
+.ui.grid > .column.row > [class*="three wide"].column,
+.ui.grid > [class*="three wide"].column,
+.ui.column.grid > [class*="three wide"].column {
+  width: 18.75% !important;
+}
+.ui.grid > .row > [class*="four wide"].column,
+.ui.grid > .column.row > [class*="four wide"].column,
+.ui.grid > [class*="four wide"].column,
+.ui.column.grid > [class*="four wide"].column {
+  width: 25% !important;
+}
+.ui.grid > .row > [class*="five wide"].column,
+.ui.grid > .column.row > [class*="five wide"].column,
+.ui.grid > [class*="five wide"].column,
+.ui.column.grid > [class*="five wide"].column {
+  width: 31.25% !important;
+}
+.ui.grid > .row > [class*="six wide"].column,
+.ui.grid > .column.row > [class*="six wide"].column,
+.ui.grid > [class*="six wide"].column,
+.ui.column.grid > [class*="six wide"].column {
+  width: 37.5% !important;
+}
+.ui.grid > .row > [class*="seven wide"].column,
+.ui.grid > .column.row > [class*="seven wide"].column,
+.ui.grid > [class*="seven wide"].column,
+.ui.column.grid > [class*="seven wide"].column {
+  width: 43.75% !important;
+}
+.ui.grid > .row > [class*="eight wide"].column,
+.ui.grid > .column.row > [class*="eight wide"].column,
+.ui.grid > [class*="eight wide"].column,
+.ui.column.grid > [class*="eight wide"].column {
+  width: 50% !important;
+}
+.ui.grid > .row > [class*="nine wide"].column,
+.ui.grid > .column.row > [class*="nine wide"].column,
+.ui.grid > [class*="nine wide"].column,
+.ui.column.grid > [class*="nine wide"].column {
+  width: 56.25% !important;
+}
+.ui.grid > .row > [class*="ten wide"].column,
+.ui.grid > .column.row > [class*="ten wide"].column,
+.ui.grid > [class*="ten wide"].column,
+.ui.column.grid > [class*="ten wide"].column {
+  width: 62.5% !important;
+}
+.ui.grid > .row > [class*="eleven wide"].column,
+.ui.grid > .column.row > [class*="eleven wide"].column,
+.ui.grid > [class*="eleven wide"].column,
+.ui.column.grid > [class*="eleven wide"].column {
+  width: 68.75% !important;
+}
+.ui.grid > .row > [class*="twelve wide"].column,
+.ui.grid > .column.row > [class*="twelve wide"].column,
+.ui.grid > [class*="twelve wide"].column,
+.ui.column.grid > [class*="twelve wide"].column {
+  width: 75% !important;
+}
+.ui.grid > .row > [class*="thirteen wide"].column,
+.ui.grid > .column.row > [class*="thirteen wide"].column,
+.ui.grid > [class*="thirteen wide"].column,
+.ui.column.grid > [class*="thirteen wide"].column {
+  width: 81.25% !important;
+}
+.ui.grid > .row > [class*="fourteen wide"].column,
+.ui.grid > .column.row > [class*="fourteen wide"].column,
+.ui.grid > [class*="fourteen wide"].column,
+.ui.column.grid > [class*="fourteen wide"].column {
+  width: 87.5% !important;
+}
+.ui.grid > .row > [class*="fifteen wide"].column,
+.ui.grid > .column.row > [class*="fifteen wide"].column,
+.ui.grid > [class*="fifteen wide"].column,
+.ui.column.grid > [class*="fifteen wide"].column {
+  width: 93.75% !important;
+}
+.ui.grid > .row > [class*="sixteen wide"].column,
+.ui.grid > .column.row > [class*="sixteen wide"].column,
+.ui.grid > [class*="sixteen wide"].column,
+.ui.column.grid > [class*="sixteen wide"].column {
+  width: 100% !important;
+}
+
+.ui.centered.grid,
+.ui.centered.grid > .row,
+.ui.grid > .centered.row {
+  text-align: center;
+  justify-content: center;
+}
+.ui.centered.grid > .column:not(.aligned):not(.justified):not(.row),
+.ui.centered.grid > .row > .column:not(.aligned):not(.justified),
+.ui.grid .centered.row > .column:not(.aligned):not(.justified) {
+  text-align: left;
+}
+.ui.grid > .centered.column,
+.ui.grid > .row > .centered.column {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.ui.relaxed.grid > .column:not(.row),
+.ui.relaxed.grid > .row > .column,
+.ui.grid > .relaxed.row > .column {
+  padding-left: 1.5rem;
+  padding-right: 1.5rem;
+}
+.ui[class*="very relaxed"].grid > .column:not(.row),
+.ui[class*="very relaxed"].grid > .row > .column,
+.ui.grid > [class*="very relaxed"].row > .column {
+  padding-left: 2.5rem;
+  padding-right: 2.5rem;
+}
+
+.ui.relaxed.grid .row + .ui.divider,
+.ui.grid .relaxed.row + .ui.divider {
+  margin-left: 1.5rem;
+  margin-right: 1.5rem;
+}
+.ui[class*="very relaxed"].grid .row + .ui.divider,
+.ui.grid [class*="very relaxed"].row + .ui.divider {
+  margin-left: 2.5rem;
+  margin-right: 2.5rem;
+}
+
+.ui[class*="middle aligned"].grid > .column:not(.row),
+.ui[class*="middle aligned"].grid > .row > .column,
+.ui.grid > [class*="middle aligned"].row > .column,
+.ui.grid > [class*="middle aligned"].column:not(.row),
+.ui.grid > .row > [class*="middle aligned"].column {
+  flex-direction: column;
+  vertical-align: middle;
+  align-self: center !important;
+}
+
+.ui[class*="center aligned"].grid > .column,
+.ui[class*="center aligned"].grid > .row > .column,
+.ui.grid > [class*="center aligned"].row > .column,
+.ui.grid > [class*="center aligned"].column.column,
+.ui.grid > .row > [class*="center aligned"].column.column {
+  text-align: center;
+  align-self: inherit;
+}
+.ui[class*="center aligned"].grid {
+  justify-content: center;
+}
+
+.ui[class*="equal width"].grid > .column:not(.row),
+.ui[class*="equal width"].grid > .row > .column,
+.ui.grid > [class*="equal width"].row > .column {
+  display: inline-block;
+  flex-grow: 1;
+}
+.ui[class*="equal width"].grid > .wide.column,
+.ui[class*="equal width"].grid > .row > .wide.column,
+.ui.grid > [class*="equal width"].row > .wide.column {
+  flex-grow: 0;
+}
+
+@media only screen and (max-width: 767.98px) {
+  .ui[class*="mobile reversed"].grid,
+  .ui[class*="mobile reversed"].grid > .row,
+  .ui.grid > [class*="mobile reversed"].row {
+    flex-direction: row-reverse;
+  }
+  .ui.stackable[class*="mobile reversed"] {
+    flex-direction: column-reverse;
+  }
+}
+
+@media only screen and (max-width: 767.98px) {
+  .ui.stackable.grid {
+    width: auto;
+    margin-left: 0 !important;
+    margin-right: 0 !important;
+  }
+  .ui.stackable.grid > .row > .wide.column,
+  .ui.stackable.grid > .wide.column,
+  .ui.stackable.grid > .column.grid > .column,
+  .ui.stackable.grid > .column.row > .column,
+  .ui.stackable.grid > .row > .column,
+  .ui.stackable.grid > .column:not(.row),
+  .ui.grid > .stackable.stackable.stackable.row > .column {
+    width: 100% !important;
+    margin: 0 !important;
+    box-shadow: none !important;
+    padding: 1rem;
+  }
+  .ui.stackable.grid:not(.vertically) > .row {
+    margin: 0;
+    padding: 0;
+  }
+
+  .ui.container > .ui.stackable.grid > .column,
+  .ui.container > .ui.stackable.grid > .row > .column {
+    padding-left: 0 !important;
+    padding-right: 0 !important;
+  }
+
+  .ui.grid .ui.stackable.grid,
+  .ui.segment:not(.vertical) .ui.stackable.page.grid {
+    margin-left: -1rem !important;
+    margin-right: -1rem !important;
+  }
+}
+
+.ui.ui.ui.compact.grid > .column:not(.row),
+.ui.ui.ui.compact.grid > .row > .column {
+  padding-left: 0.5rem;
+  padding-right: 0.5rem;
+}
+.ui.ui.ui.compact.grid > * {
+  padding-left: 0.5rem;
+  padding-right: 0.5rem;
+}
+
+.ui.ui.ui.compact.grid > .row {
+  padding-top: 0.5rem;
+  padding-bottom: 0.5rem;
+}
+
+.ui.ui.ui.compact.grid > .column:not(.row) {
+  padding-top: 0.5rem;
+  padding-bottom: 0.5rem;
+}
diff --git a/web_src/css/modules/message.css b/web_src/css/modules/message.css
index 22dd03232..a29603cd9 100644
--- a/web_src/css/modules/message.css
+++ b/web_src/css/modules/message.css
@@ -1,3 +1,6 @@
+/* based on Fomantic UI message module, with just the parts extracted that we use. If you find any
+   unused rules here after refactoring, please remove them. */
+
 .ui.message {
   background: var(--color-box-body);
   color: var(--color-text);
diff --git a/web_src/css/repo.css b/web_src/css/repo.css
index 0eba77dbf..128748621 100644
--- a/web_src/css/repo.css
+++ b/web_src/css/repo.css
@@ -143,41 +143,31 @@
   margin-bottom: 12px;
 }
 
-.repository #clone-panel #repo-clone-url {
+.repository .clone-panel #repo-clone-url {
   width: 320px;
   border-radius: 0;
 }
 
-@media (min-width: 768px) and (max-width: 991.98px) {
-  .repository #clone-panel #repo-clone-url {
+@media (max-width: 991.98px) {
+  .repository .clone-panel #repo-clone-url {
     width: 200px;
   }
 }
 
-@media (max-width: 767.98px) {
-  .repository #clone-panel #repo-clone-url {
-    width: 200px;
-  }
+.repository .ui.action.input.clone-panel > button + button,
+.repository .ui.action.input.clone-panel > button + input {
+  margin-left: -1px; /* make the borders overlap to avoid double borders */
 }
 
-.repository #clone-panel #repo-clone-https,
-.repository #clone-panel #repo-clone-ssh {
-  border-right: none;
-}
-
-.repository #clone-panel #more-btn {
-  border-left: none;
-}
-
-.repository #clone-panel button:first-of-type {
+.repository .clone-panel > button:first-of-type {
   border-radius: var(--border-radius) 0 0 var(--border-radius) !important;
 }
 
-.repository #clone-panel button:last-of-type {
+.repository .clone-panel > button:last-of-type {
   border-radius: 0 var(--border-radius) var(--border-radius) 0 !important;
 }
 
-.repository #clone-panel .dropdown .menu {
+.repository .clone-panel .dropdown .menu {
   right: 0 !important;
   left: auto !important;
 }
@@ -1758,10 +1748,6 @@
   font-weight: var(--font-weight-normal);
 }
 
-.repository.quickstart .guide .clone.button:first-child {
-  border-radius: var(--border-radius) 0 0 var(--border-radius);
-}
-
 .repository.quickstart .guide #repo-clone-url {
   border-radius: 0;
   padding: 5px 10px;
diff --git a/web_src/css/repo/header.css b/web_src/css/repo/header.css
index a262b5b3e..482608a1a 100644
--- a/web_src/css/repo/header.css
+++ b/web_src/css/repo/header.css
@@ -71,6 +71,7 @@
 }
 
 .repository .header-wrapper {
+  padding-top: 12px;
   background-color: var(--color-header-wrapper);
 }
 
diff --git a/web_src/css/repo/wiki.css b/web_src/css/repo/wiki.css
index 1302e9cb5..ba502d321 100644
--- a/web_src/css/repo/wiki.css
+++ b/web_src/css/repo/wiki.css
@@ -21,6 +21,7 @@
 
 .repository.wiki .wiki-content-parts .markup {
   border: 1px solid var(--color-secondary);
+  border-radius: var(--border-radius);
   padding: 1em;
   margin-top: 1em;
   font-size: 1em;
@@ -58,7 +59,7 @@
 }
 
 @media (max-width: 767.98px) {
-  .repository.wiki #clone-panel #repo-clone-url {
+  .repository.wiki .clone-panel #repo-clone-url {
     width: 160px;
   }
   .repository.wiki .wiki-content-main.with-sidebar,
diff --git a/web_src/css/review.css b/web_src/css/review.css
index 62da25b20..d5b675a65 100644
--- a/web_src/css/review.css
+++ b/web_src/css/review.css
@@ -198,6 +198,10 @@
   margin: 0 0 0 3em;
 }
 
+.diff-file-body.binary {
+  padding: 5px 10px;
+}
+
 .file-comment {
   color: var(--color-text);
 }
diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css
index 4e38d75f6..9cf8907e4 100644
--- a/web_src/css/themes/theme-gitea-dark.css
+++ b/web_src/css/themes/theme-gitea-dark.css
@@ -180,16 +180,16 @@
   --color-orange-badge-hover-bg: #f2711c4d;
   --color-git: #f05133;
   /* target-based colors */
-  --color-body: #1e2224;
+  --color-body: #1c1f25;
   --color-box-header: #1a1d1f;
   --color-box-body: #14171a;
   --color-box-body-highlight: #121517;
   --color-text-dark: #f8f8f9;
-  --color-text: #ced2d5;
-  --color-text-light: #bec4c8;
-  --color-text-light-1: #acb3b8;
-  --color-text-light-2: #8d969c;
-  --color-text-light-3: #747f87;
+  --color-text: #d1d5d8;
+  --color-text-light: #bdc3c7;
+  --color-text-light-1: #a8afb5;
+  --color-text-light-2: #929ba2;
+  --color-text-light-3: #7c8790;
   --color-footer: var(--color-nav-bg);
   --color-timeline: #353c42;
   --color-input-text: var(--color-text-dark);
diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css
index eded03e37..2ac83eefe 100644
--- a/web_src/css/themes/theme-gitea-light.css
+++ b/web_src/css/themes/theme-gitea-light.css
@@ -184,20 +184,20 @@
   --color-box-header: #f1f3f5;
   --color-box-body: #ffffff;
   --color-box-body-highlight: #f4faff;
-  --color-text-dark: #03080d;
-  --color-text: #1c2126;
-  --color-text-light: #3c434a;
-  --color-text-light-1: #4b5259;
-  --color-text-light-2: #6a7178;
-  --color-text-light-3: #899097;
+  --color-text-dark: #01050a;
+  --color-text: #181c21;
+  --color-text-light: #30363b;
+  --color-text-light-1: #40474d;
+  --color-text-light-2: #5b6167;
+  --color-text-light-3: #747c84;
   --color-footer: var(--color-nav-bg);
   --color-timeline: #d0d7de;
   --color-input-text: var(--color-text-dark);
-  --color-input-background: #f8f9fb;
+  --color-input-background: #fff;
   --color-input-toggle-background: #d0d7de;
   --color-input-border: var(--color-secondary);
   --color-input-border-hover: var(--color-secondary-dark-1);
-  --color-header-wrapper: #fafbfc;
+  --color-header-wrapper: #f9fafb;
   --color-light: #00001706;
   --color-light-mimic-enabled: rgba(0, 0, 0, calc(6 / 255 * 222 / 255 / var(--opacity-disabled)));
   --color-light-border: #0000171d;
@@ -224,7 +224,7 @@
   --color-reaction-active-bg: var(--color-primary-light-6);
   --color-tooltip-text: #fbfdff;
   --color-tooltip-bg: #000017f0;
-  --color-nav-bg: #f8f9fb;
+  --color-nav-bg: #f6f7fa;
   --color-nav-hover-bg: var(--color-secondary-light-1);
   --color-nav-text: var(--color-text);
   --color-label-text: var(--color-text);
diff --git a/web_src/css/user.css b/web_src/css/user.css
index 9157a53e7..ece7d9b2c 100644
--- a/web_src/css/user.css
+++ b/web_src/css/user.css
@@ -125,6 +125,10 @@
   border: 1px solid var(--color-secondary);
 }
 
+#notification_div {
+  padding-top: 15px;
+}
+
 #notification_table {
   background: var(--color-box-body);
   border: 1px solid var(--color-secondary);
diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css
index 6f45c1944..099bb94c3 100644
--- a/web_src/fomantic/build/semantic.css
+++ b/web_src/fomantic/build/semantic.css
@@ -7340,2009 +7340,6 @@ select.ui.dropdown {
          Theme Overrides
 *******************************/
 
-/*******************************
-         Site Overrides
-*******************************/
-/*!
- * # Fomantic-UI - Grid
- * http://github.com/fomantic/Fomantic-UI/
- *
- *
- * Released under the MIT license
- * http://opensource.org/licenses/MIT
- *
- */
-
-/*******************************
-            Standard
-*******************************/
-
-.ui.grid {
-  display: flex;
-  flex-direction: row;
-  flex-wrap: wrap;
-  align-items: stretch;
-  padding: 0;
-}
-
-/*----------------------
-      Remove Gutters
------------------------*/
-
-.ui.grid {
-  margin-top: -1rem;
-  margin-bottom: -1rem;
-  margin-left: -1rem;
-  margin-right: -1rem;
-}
-
-.ui.relaxed.grid {
-  margin-left: -1.5rem;
-  margin-right: -1.5rem;
-}
-
-.ui[class*="very relaxed"].grid {
-  margin-left: -2.5rem;
-  margin-right: -2.5rem;
-}
-
-/* Preserve Rows Spacing on Consecutive Grids */
-
-.ui.grid + .grid {
-  margin-top: 1rem;
-}
-
-/*-------------------
-       Columns
---------------------*/
-
-/* Standard 16 column */
-
-.ui.grid > .column:not(.row),
-.ui.grid > .row > .column {
-  position: relative;
-  display: inline-block;
-  width: 6.25%;
-  padding-left: 1rem;
-  padding-right: 1rem;
-  vertical-align: top;
-}
-
-.ui.grid > * {
-  padding-left: 1rem;
-  padding-right: 1rem;
-}
-
-/*-------------------
-        Rows
---------------------*/
-
-.ui.grid > .row {
-  position: relative;
-  display: flex;
-  flex-direction: row;
-  flex-wrap: wrap;
-  justify-content: inherit;
-  align-items: stretch;
-  width: 100% !important;
-  padding: 0;
-  padding-top: 1rem;
-  padding-bottom: 1rem;
-}
-
-/*-------------------
-       Columns
---------------------*/
-
-/* Vertical padding when no rows */
-
-.ui.grid > .column:not(.row) {
-  padding-top: 1rem;
-  padding-bottom: 1rem;
-}
-
-.ui.grid > .row > .column {
-  margin-top: 0;
-  margin-bottom: 0;
-}
-
-/*-------------------
-      Content
---------------------*/
-
-.ui.grid > .row > img,
-.ui.grid > .row > .column > img {
-  max-width: 100%;
-}
-
-/*-------------------
-    Loose Coupling
---------------------*/
-
-/* Collapse Margin on Consecutive Grid */
-
-.ui.grid > .ui.grid:first-child {
-  margin-top: 0;
-}
-
-.ui.grid > .ui.grid:last-child {
-  margin-bottom: 0;
-}
-
-/* Segment inside Aligned Grid */
-
-.ui.grid .aligned.row > .column > .segment:not(.compact):not(.attached),
-.ui.aligned.grid .column > .segment:not(.compact):not(.attached) {
-  width: 100%;
-}
-
-/* Align Dividers with Gutter */
-
-.ui.grid .row + .ui.divider {
-  flex-grow: 1;
-  margin: 1rem 1rem;
-}
-
-.ui.grid .column + .ui.vertical.divider {
-  height: calc(50% - 1rem);
-}
-
-/* Remove Border on Last Horizontal Segment */
-
-.ui.grid > .row > .column:last-child > .horizontal.segment,
-.ui.grid > .column:last-child > .horizontal.segment {
-  box-shadow: none;
-}
-
-/*******************************
-           Variations
-*******************************/
-
-/*-----------------------
-         Page Grid
-  -------------------------*/
-
-@media only screen and (max-width: 767.98px) {
-  .ui.page.grid {
-    width: auto;
-    padding-left: 0;
-    padding-right: 0;
-    margin-left: 0;
-    margin-right: 0;
-  }
-}
-
-@media only screen and (min-width: 768px) and (max-width: 991.98px) {
-  .ui.page.grid {
-    width: auto;
-    margin-left: 0;
-    margin-right: 0;
-    padding-left: 2em;
-    padding-right: 2em;
-  }
-}
-
-@media only screen and (min-width: 992px) and (max-width: 1199.98px) {
-  .ui.page.grid {
-    width: auto;
-    margin-left: 0;
-    margin-right: 0;
-    padding-left: 3%;
-    padding-right: 3%;
-  }
-}
-
-@media only screen and (min-width: 1200px) and (max-width: 1919.98px) {
-  .ui.page.grid {
-    width: auto;
-    margin-left: 0;
-    margin-right: 0;
-    padding-left: 15%;
-    padding-right: 15%;
-  }
-}
-
-@media only screen and (min-width: 1920px) {
-  .ui.page.grid {
-    width: auto;
-    margin-left: 0;
-    margin-right: 0;
-    padding-left: 23%;
-    padding-right: 23%;
-  }
-}
-
-/*-------------------
-     Column Count
---------------------*/
-
-/* Assume full width with one column */
-
-.ui.grid > .column:only-child,
-.ui.grid > .row > .column:only-child {
-  width: 100%;
-}
-
-/* Grid Based */
-
-.ui[class*="one column"].grid > .row > .column,
-.ui[class*="one column"].grid > .column:not(.row) {
-  width: 100%;
-}
-
-.ui[class*="two column"].grid > .row > .column,
-.ui[class*="two column"].grid > .column:not(.row) {
-  width: 50%;
-}
-
-.ui[class*="three column"].grid > .row > .column,
-.ui[class*="three column"].grid > .column:not(.row) {
-  width: 33.33333333%;
-}
-
-.ui[class*="four column"].grid > .row > .column,
-.ui[class*="four column"].grid > .column:not(.row) {
-  width: 25%;
-}
-
-.ui[class*="five column"].grid > .row > .column,
-.ui[class*="five column"].grid > .column:not(.row) {
-  width: 20%;
-}
-
-.ui[class*="six column"].grid > .row > .column,
-.ui[class*="six column"].grid > .column:not(.row) {
-  width: 16.66666667%;
-}
-
-.ui[class*="seven column"].grid > .row > .column,
-.ui[class*="seven column"].grid > .column:not(.row) {
-  width: 14.28571429%;
-}
-
-.ui[class*="eight column"].grid > .row > .column,
-.ui[class*="eight column"].grid > .column:not(.row) {
-  width: 12.5%;
-}
-
-.ui[class*="nine column"].grid > .row > .column,
-.ui[class*="nine column"].grid > .column:not(.row) {
-  width: 11.11111111%;
-}
-
-.ui[class*="ten column"].grid > .row > .column,
-.ui[class*="ten column"].grid > .column:not(.row) {
-  width: 10%;
-}
-
-.ui[class*="eleven column"].grid > .row > .column,
-.ui[class*="eleven column"].grid > .column:not(.row) {
-  width: 9.09090909%;
-}
-
-.ui[class*="twelve column"].grid > .row > .column,
-.ui[class*="twelve column"].grid > .column:not(.row) {
-  width: 8.33333333%;
-}
-
-.ui[class*="thirteen column"].grid > .row > .column,
-.ui[class*="thirteen column"].grid > .column:not(.row) {
-  width: 7.69230769%;
-}
-
-.ui[class*="fourteen column"].grid > .row > .column,
-.ui[class*="fourteen column"].grid > .column:not(.row) {
-  width: 7.14285714%;
-}
-
-.ui[class*="fifteen column"].grid > .row > .column,
-.ui[class*="fifteen column"].grid > .column:not(.row) {
-  width: 6.66666667%;
-}
-
-.ui[class*="sixteen column"].grid > .row > .column,
-.ui[class*="sixteen column"].grid > .column:not(.row) {
-  width: 6.25%;
-}
-
-/* Row Based Overrides */
-
-.ui.grid > [class*="one column"].row > .column {
-  width: 100% !important;
-}
-
-.ui.grid > [class*="two column"].row > .column {
-  width: 50% !important;
-}
-
-.ui.grid > [class*="three column"].row > .column {
-  width: 33.33333333% !important;
-}
-
-.ui.grid > [class*="four column"].row > .column {
-  width: 25% !important;
-}
-
-.ui.grid > [class*="five column"].row > .column {
-  width: 20% !important;
-}
-
-.ui.grid > [class*="six column"].row > .column {
-  width: 16.66666667% !important;
-}
-
-.ui.grid > [class*="seven column"].row > .column {
-  width: 14.28571429% !important;
-}
-
-.ui.grid > [class*="eight column"].row > .column {
-  width: 12.5% !important;
-}
-
-.ui.grid > [class*="nine column"].row > .column {
-  width: 11.11111111% !important;
-}
-
-.ui.grid > [class*="ten column"].row > .column {
-  width: 10% !important;
-}
-
-.ui.grid > [class*="eleven column"].row > .column {
-  width: 9.09090909% !important;
-}
-
-.ui.grid > [class*="twelve column"].row > .column {
-  width: 8.33333333% !important;
-}
-
-.ui.grid > [class*="thirteen column"].row > .column {
-  width: 7.69230769% !important;
-}
-
-.ui.grid > [class*="fourteen column"].row > .column {
-  width: 7.14285714% !important;
-}
-
-.ui.grid > [class*="fifteen column"].row > .column {
-  width: 6.66666667% !important;
-}
-
-.ui.grid > [class*="sixteen column"].row > .column {
-  width: 6.25% !important;
-}
-
-/* Celled Page */
-
-.ui.celled.page.grid {
-  box-shadow: none;
-}
-
-/*-------------------
-    Column Width
---------------------*/
-
-/* Sizing Combinations */
-
-.ui.grid > .row > [class*="one wide"].column,
-.ui.grid > .column.row > [class*="one wide"].column,
-.ui.grid > [class*="one wide"].column,
-.ui.column.grid > [class*="one wide"].column {
-  width: 6.25% !important;
-}
-
-.ui.grid > .row > [class*="two wide"].column,
-.ui.grid > .column.row > [class*="two wide"].column,
-.ui.grid > [class*="two wide"].column,
-.ui.column.grid > [class*="two wide"].column {
-  width: 12.5% !important;
-}
-
-.ui.grid > .row > [class*="three wide"].column,
-.ui.grid > .column.row > [class*="three wide"].column,
-.ui.grid > [class*="three wide"].column,
-.ui.column.grid > [class*="three wide"].column {
-  width: 18.75% !important;
-}
-
-.ui.grid > .row > [class*="four wide"].column,
-.ui.grid > .column.row > [class*="four wide"].column,
-.ui.grid > [class*="four wide"].column,
-.ui.column.grid > [class*="four wide"].column {
-  width: 25% !important;
-}
-
-.ui.grid > .row > [class*="five wide"].column,
-.ui.grid > .column.row > [class*="five wide"].column,
-.ui.grid > [class*="five wide"].column,
-.ui.column.grid > [class*="five wide"].column {
-  width: 31.25% !important;
-}
-
-.ui.grid > .row > [class*="six wide"].column,
-.ui.grid > .column.row > [class*="six wide"].column,
-.ui.grid > [class*="six wide"].column,
-.ui.column.grid > [class*="six wide"].column {
-  width: 37.5% !important;
-}
-
-.ui.grid > .row > [class*="seven wide"].column,
-.ui.grid > .column.row > [class*="seven wide"].column,
-.ui.grid > [class*="seven wide"].column,
-.ui.column.grid > [class*="seven wide"].column {
-  width: 43.75% !important;
-}
-
-.ui.grid > .row > [class*="eight wide"].column,
-.ui.grid > .column.row > [class*="eight wide"].column,
-.ui.grid > [class*="eight wide"].column,
-.ui.column.grid > [class*="eight wide"].column {
-  width: 50% !important;
-}
-
-.ui.grid > .row > [class*="nine wide"].column,
-.ui.grid > .column.row > [class*="nine wide"].column,
-.ui.grid > [class*="nine wide"].column,
-.ui.column.grid > [class*="nine wide"].column {
-  width: 56.25% !important;
-}
-
-.ui.grid > .row > [class*="ten wide"].column,
-.ui.grid > .column.row > [class*="ten wide"].column,
-.ui.grid > [class*="ten wide"].column,
-.ui.column.grid > [class*="ten wide"].column {
-  width: 62.5% !important;
-}
-
-.ui.grid > .row > [class*="eleven wide"].column,
-.ui.grid > .column.row > [class*="eleven wide"].column,
-.ui.grid > [class*="eleven wide"].column,
-.ui.column.grid > [class*="eleven wide"].column {
-  width: 68.75% !important;
-}
-
-.ui.grid > .row > [class*="twelve wide"].column,
-.ui.grid > .column.row > [class*="twelve wide"].column,
-.ui.grid > [class*="twelve wide"].column,
-.ui.column.grid > [class*="twelve wide"].column {
-  width: 75% !important;
-}
-
-.ui.grid > .row > [class*="thirteen wide"].column,
-.ui.grid > .column.row > [class*="thirteen wide"].column,
-.ui.grid > [class*="thirteen wide"].column,
-.ui.column.grid > [class*="thirteen wide"].column {
-  width: 81.25% !important;
-}
-
-.ui.grid > .row > [class*="fourteen wide"].column,
-.ui.grid > .column.row > [class*="fourteen wide"].column,
-.ui.grid > [class*="fourteen wide"].column,
-.ui.column.grid > [class*="fourteen wide"].column {
-  width: 87.5% !important;
-}
-
-.ui.grid > .row > [class*="fifteen wide"].column,
-.ui.grid > .column.row > [class*="fifteen wide"].column,
-.ui.grid > [class*="fifteen wide"].column,
-.ui.column.grid > [class*="fifteen wide"].column {
-  width: 93.75% !important;
-}
-
-.ui.grid > .row > [class*="sixteen wide"].column,
-.ui.grid > .column.row > [class*="sixteen wide"].column,
-.ui.grid > [class*="sixteen wide"].column,
-.ui.column.grid > [class*="sixteen wide"].column {
-  width: 100% !important;
-}
-
-/*----------------------
-    Width per Device
------------------------*/
-
-/* Mobile Sizing Combinations */
-
-@media only screen and (min-width: 320px) and (max-width: 767.98px) {
-  .ui.grid > .row > [class*="one wide mobile"].column,
-  .ui.grid > .column.row > [class*="one wide mobile"].column,
-  .ui.grid > [class*="one wide mobile"].column,
-  .ui.column.grid > [class*="one wide mobile"].column {
-    width: 6.25% !important;
-  }
-
-  .ui.grid > .row > [class*="two wide mobile"].column,
-  .ui.grid > .column.row > [class*="two wide mobile"].column,
-  .ui.grid > [class*="two wide mobile"].column,
-  .ui.column.grid > [class*="two wide mobile"].column {
-    width: 12.5% !important;
-  }
-
-  .ui.grid > .row > [class*="three wide mobile"].column,
-  .ui.grid > .column.row > [class*="three wide mobile"].column,
-  .ui.grid > [class*="three wide mobile"].column,
-  .ui.column.grid > [class*="three wide mobile"].column {
-    width: 18.75% !important;
-  }
-
-  .ui.grid > .row > [class*="four wide mobile"].column,
-  .ui.grid > .column.row > [class*="four wide mobile"].column,
-  .ui.grid > [class*="four wide mobile"].column,
-  .ui.column.grid > [class*="four wide mobile"].column {
-    width: 25% !important;
-  }
-
-  .ui.grid > .row > [class*="five wide mobile"].column,
-  .ui.grid > .column.row > [class*="five wide mobile"].column,
-  .ui.grid > [class*="five wide mobile"].column,
-  .ui.column.grid > [class*="five wide mobile"].column {
-    width: 31.25% !important;
-  }
-
-  .ui.grid > .row > [class*="six wide mobile"].column,
-  .ui.grid > .column.row > [class*="six wide mobile"].column,
-  .ui.grid > [class*="six wide mobile"].column,
-  .ui.column.grid > [class*="six wide mobile"].column {
-    width: 37.5% !important;
-  }
-
-  .ui.grid > .row > [class*="seven wide mobile"].column,
-  .ui.grid > .column.row > [class*="seven wide mobile"].column,
-  .ui.grid > [class*="seven wide mobile"].column,
-  .ui.column.grid > [class*="seven wide mobile"].column {
-    width: 43.75% !important;
-  }
-
-  .ui.grid > .row > [class*="eight wide mobile"].column,
-  .ui.grid > .column.row > [class*="eight wide mobile"].column,
-  .ui.grid > [class*="eight wide mobile"].column,
-  .ui.column.grid > [class*="eight wide mobile"].column {
-    width: 50% !important;
-  }
-
-  .ui.grid > .row > [class*="nine wide mobile"].column,
-  .ui.grid > .column.row > [class*="nine wide mobile"].column,
-  .ui.grid > [class*="nine wide mobile"].column,
-  .ui.column.grid > [class*="nine wide mobile"].column {
-    width: 56.25% !important;
-  }
-
-  .ui.grid > .row > [class*="ten wide mobile"].column,
-  .ui.grid > .column.row > [class*="ten wide mobile"].column,
-  .ui.grid > [class*="ten wide mobile"].column,
-  .ui.column.grid > [class*="ten wide mobile"].column {
-    width: 62.5% !important;
-  }
-
-  .ui.grid > .row > [class*="eleven wide mobile"].column,
-  .ui.grid > .column.row > [class*="eleven wide mobile"].column,
-  .ui.grid > [class*="eleven wide mobile"].column,
-  .ui.column.grid > [class*="eleven wide mobile"].column {
-    width: 68.75% !important;
-  }
-
-  .ui.grid > .row > [class*="twelve wide mobile"].column,
-  .ui.grid > .column.row > [class*="twelve wide mobile"].column,
-  .ui.grid > [class*="twelve wide mobile"].column,
-  .ui.column.grid > [class*="twelve wide mobile"].column {
-    width: 75% !important;
-  }
-
-  .ui.grid > .row > [class*="thirteen wide mobile"].column,
-  .ui.grid > .column.row > [class*="thirteen wide mobile"].column,
-  .ui.grid > [class*="thirteen wide mobile"].column,
-  .ui.column.grid > [class*="thirteen wide mobile"].column {
-    width: 81.25% !important;
-  }
-
-  .ui.grid > .row > [class*="fourteen wide mobile"].column,
-  .ui.grid > .column.row > [class*="fourteen wide mobile"].column,
-  .ui.grid > [class*="fourteen wide mobile"].column,
-  .ui.column.grid > [class*="fourteen wide mobile"].column {
-    width: 87.5% !important;
-  }
-
-  .ui.grid > .row > [class*="fifteen wide mobile"].column,
-  .ui.grid > .column.row > [class*="fifteen wide mobile"].column,
-  .ui.grid > [class*="fifteen wide mobile"].column,
-  .ui.column.grid > [class*="fifteen wide mobile"].column {
-    width: 93.75% !important;
-  }
-
-  .ui.grid > .row > [class*="sixteen wide mobile"].column,
-  .ui.grid > .column.row > [class*="sixteen wide mobile"].column,
-  .ui.grid > [class*="sixteen wide mobile"].column,
-  .ui.column.grid > [class*="sixteen wide mobile"].column {
-    width: 100% !important;
-  }
-}
-
-/* Tablet Sizing Combinations */
-
-@media only screen and (min-width: 768px) and (max-width: 991.98px) {
-  .ui.grid > .row > [class*="one wide tablet"].column,
-  .ui.grid > .column.row > [class*="one wide tablet"].column,
-  .ui.grid > [class*="one wide tablet"].column,
-  .ui.column.grid > [class*="one wide tablet"].column {
-    width: 6.25% !important;
-  }
-
-  .ui.grid > .row > [class*="two wide tablet"].column,
-  .ui.grid > .column.row > [class*="two wide tablet"].column,
-  .ui.grid > [class*="two wide tablet"].column,
-  .ui.column.grid > [class*="two wide tablet"].column {
-    width: 12.5% !important;
-  }
-
-  .ui.grid > .row > [class*="three wide tablet"].column,
-  .ui.grid > .column.row > [class*="three wide tablet"].column,
-  .ui.grid > [class*="three wide tablet"].column,
-  .ui.column.grid > [class*="three wide tablet"].column {
-    width: 18.75% !important;
-  }
-
-  .ui.grid > .row > [class*="four wide tablet"].column,
-  .ui.grid > .column.row > [class*="four wide tablet"].column,
-  .ui.grid > [class*="four wide tablet"].column,
-  .ui.column.grid > [class*="four wide tablet"].column {
-    width: 25% !important;
-  }
-
-  .ui.grid > .row > [class*="five wide tablet"].column,
-  .ui.grid > .column.row > [class*="five wide tablet"].column,
-  .ui.grid > [class*="five wide tablet"].column,
-  .ui.column.grid > [class*="five wide tablet"].column {
-    width: 31.25% !important;
-  }
-
-  .ui.grid > .row > [class*="six wide tablet"].column,
-  .ui.grid > .column.row > [class*="six wide tablet"].column,
-  .ui.grid > [class*="six wide tablet"].column,
-  .ui.column.grid > [class*="six wide tablet"].column {
-    width: 37.5% !important;
-  }
-
-  .ui.grid > .row > [class*="seven wide tablet"].column,
-  .ui.grid > .column.row > [class*="seven wide tablet"].column,
-  .ui.grid > [class*="seven wide tablet"].column,
-  .ui.column.grid > [class*="seven wide tablet"].column {
-    width: 43.75% !important;
-  }
-
-  .ui.grid > .row > [class*="eight wide tablet"].column,
-  .ui.grid > .column.row > [class*="eight wide tablet"].column,
-  .ui.grid > [class*="eight wide tablet"].column,
-  .ui.column.grid > [class*="eight wide tablet"].column {
-    width: 50% !important;
-  }
-
-  .ui.grid > .row > [class*="nine wide tablet"].column,
-  .ui.grid > .column.row > [class*="nine wide tablet"].column,
-  .ui.grid > [class*="nine wide tablet"].column,
-  .ui.column.grid > [class*="nine wide tablet"].column {
-    width: 56.25% !important;
-  }
-
-  .ui.grid > .row > [class*="ten wide tablet"].column,
-  .ui.grid > .column.row > [class*="ten wide tablet"].column,
-  .ui.grid > [class*="ten wide tablet"].column,
-  .ui.column.grid > [class*="ten wide tablet"].column {
-    width: 62.5% !important;
-  }
-
-  .ui.grid > .row > [class*="eleven wide tablet"].column,
-  .ui.grid > .column.row > [class*="eleven wide tablet"].column,
-  .ui.grid > [class*="eleven wide tablet"].column,
-  .ui.column.grid > [class*="eleven wide tablet"].column {
-    width: 68.75% !important;
-  }
-
-  .ui.grid > .row > [class*="twelve wide tablet"].column,
-  .ui.grid > .column.row > [class*="twelve wide tablet"].column,
-  .ui.grid > [class*="twelve wide tablet"].column,
-  .ui.column.grid > [class*="twelve wide tablet"].column {
-    width: 75% !important;
-  }
-
-  .ui.grid > .row > [class*="thirteen wide tablet"].column,
-  .ui.grid > .column.row > [class*="thirteen wide tablet"].column,
-  .ui.grid > [class*="thirteen wide tablet"].column,
-  .ui.column.grid > [class*="thirteen wide tablet"].column {
-    width: 81.25% !important;
-  }
-
-  .ui.grid > .row > [class*="fourteen wide tablet"].column,
-  .ui.grid > .column.row > [class*="fourteen wide tablet"].column,
-  .ui.grid > [class*="fourteen wide tablet"].column,
-  .ui.column.grid > [class*="fourteen wide tablet"].column {
-    width: 87.5% !important;
-  }
-
-  .ui.grid > .row > [class*="fifteen wide tablet"].column,
-  .ui.grid > .column.row > [class*="fifteen wide tablet"].column,
-  .ui.grid > [class*="fifteen wide tablet"].column,
-  .ui.column.grid > [class*="fifteen wide tablet"].column {
-    width: 93.75% !important;
-  }
-
-  .ui.grid > .row > [class*="sixteen wide tablet"].column,
-  .ui.grid > .column.row > [class*="sixteen wide tablet"].column,
-  .ui.grid > [class*="sixteen wide tablet"].column,
-  .ui.column.grid > [class*="sixteen wide tablet"].column {
-    width: 100% !important;
-  }
-}
-
-/* Computer/Desktop Sizing Combinations */
-
-@media only screen and (min-width: 992px) {
-  .ui.grid > .row > [class*="one wide computer"].column,
-  .ui.grid > .column.row > [class*="one wide computer"].column,
-  .ui.grid > [class*="one wide computer"].column,
-  .ui.column.grid > [class*="one wide computer"].column {
-    width: 6.25% !important;
-  }
-
-  .ui.grid > .row > [class*="two wide computer"].column,
-  .ui.grid > .column.row > [class*="two wide computer"].column,
-  .ui.grid > [class*="two wide computer"].column,
-  .ui.column.grid > [class*="two wide computer"].column {
-    width: 12.5% !important;
-  }
-
-  .ui.grid > .row > [class*="three wide computer"].column,
-  .ui.grid > .column.row > [class*="three wide computer"].column,
-  .ui.grid > [class*="three wide computer"].column,
-  .ui.column.grid > [class*="three wide computer"].column {
-    width: 18.75% !important;
-  }
-
-  .ui.grid > .row > [class*="four wide computer"].column,
-  .ui.grid > .column.row > [class*="four wide computer"].column,
-  .ui.grid > [class*="four wide computer"].column,
-  .ui.column.grid > [class*="four wide computer"].column {
-    width: 25% !important;
-  }
-
-  .ui.grid > .row > [class*="five wide computer"].column,
-  .ui.grid > .column.row > [class*="five wide computer"].column,
-  .ui.grid > [class*="five wide computer"].column,
-  .ui.column.grid > [class*="five wide computer"].column {
-    width: 31.25% !important;
-  }
-
-  .ui.grid > .row > [class*="six wide computer"].column,
-  .ui.grid > .column.row > [class*="six wide computer"].column,
-  .ui.grid > [class*="six wide computer"].column,
-  .ui.column.grid > [class*="six wide computer"].column {
-    width: 37.5% !important;
-  }
-
-  .ui.grid > .row > [class*="seven wide computer"].column,
-  .ui.grid > .column.row > [class*="seven wide computer"].column,
-  .ui.grid > [class*="seven wide computer"].column,
-  .ui.column.grid > [class*="seven wide computer"].column {
-    width: 43.75% !important;
-  }
-
-  .ui.grid > .row > [class*="eight wide computer"].column,
-  .ui.grid > .column.row > [class*="eight wide computer"].column,
-  .ui.grid > [class*="eight wide computer"].column,
-  .ui.column.grid > [class*="eight wide computer"].column {
-    width: 50% !important;
-  }
-
-  .ui.grid > .row > [class*="nine wide computer"].column,
-  .ui.grid > .column.row > [class*="nine wide computer"].column,
-  .ui.grid > [class*="nine wide computer"].column,
-  .ui.column.grid > [class*="nine wide computer"].column {
-    width: 56.25% !important;
-  }
-
-  .ui.grid > .row > [class*="ten wide computer"].column,
-  .ui.grid > .column.row > [class*="ten wide computer"].column,
-  .ui.grid > [class*="ten wide computer"].column,
-  .ui.column.grid > [class*="ten wide computer"].column {
-    width: 62.5% !important;
-  }
-
-  .ui.grid > .row > [class*="eleven wide computer"].column,
-  .ui.grid > .column.row > [class*="eleven wide computer"].column,
-  .ui.grid > [class*="eleven wide computer"].column,
-  .ui.column.grid > [class*="eleven wide computer"].column {
-    width: 68.75% !important;
-  }
-
-  .ui.grid > .row > [class*="twelve wide computer"].column,
-  .ui.grid > .column.row > [class*="twelve wide computer"].column,
-  .ui.grid > [class*="twelve wide computer"].column,
-  .ui.column.grid > [class*="twelve wide computer"].column {
-    width: 75% !important;
-  }
-
-  .ui.grid > .row > [class*="thirteen wide computer"].column,
-  .ui.grid > .column.row > [class*="thirteen wide computer"].column,
-  .ui.grid > [class*="thirteen wide computer"].column,
-  .ui.column.grid > [class*="thirteen wide computer"].column {
-    width: 81.25% !important;
-  }
-
-  .ui.grid > .row > [class*="fourteen wide computer"].column,
-  .ui.grid > .column.row > [class*="fourteen wide computer"].column,
-  .ui.grid > [class*="fourteen wide computer"].column,
-  .ui.column.grid > [class*="fourteen wide computer"].column {
-    width: 87.5% !important;
-  }
-
-  .ui.grid > .row > [class*="fifteen wide computer"].column,
-  .ui.grid > .column.row > [class*="fifteen wide computer"].column,
-  .ui.grid > [class*="fifteen wide computer"].column,
-  .ui.column.grid > [class*="fifteen wide computer"].column {
-    width: 93.75% !important;
-  }
-
-  .ui.grid > .row > [class*="sixteen wide computer"].column,
-  .ui.grid > .column.row > [class*="sixteen wide computer"].column,
-  .ui.grid > [class*="sixteen wide computer"].column,
-  .ui.column.grid > [class*="sixteen wide computer"].column {
-    width: 100% !important;
-  }
-}
-
-/* Large Monitor Sizing Combinations */
-
-@media only screen and (min-width: 1200px) and (max-width: 1919.98px) {
-  .ui.grid > .row > [class*="one wide large screen"].column,
-  .ui.grid > .column.row > [class*="one wide large screen"].column,
-  .ui.grid > [class*="one wide large screen"].column,
-  .ui.column.grid > [class*="one wide large screen"].column {
-    width: 6.25% !important;
-  }
-
-  .ui.grid > .row > [class*="two wide large screen"].column,
-  .ui.grid > .column.row > [class*="two wide large screen"].column,
-  .ui.grid > [class*="two wide large screen"].column,
-  .ui.column.grid > [class*="two wide large screen"].column {
-    width: 12.5% !important;
-  }
-
-  .ui.grid > .row > [class*="three wide large screen"].column,
-  .ui.grid > .column.row > [class*="three wide large screen"].column,
-  .ui.grid > [class*="three wide large screen"].column,
-  .ui.column.grid > [class*="three wide large screen"].column {
-    width: 18.75% !important;
-  }
-
-  .ui.grid > .row > [class*="four wide large screen"].column,
-  .ui.grid > .column.row > [class*="four wide large screen"].column,
-  .ui.grid > [class*="four wide large screen"].column,
-  .ui.column.grid > [class*="four wide large screen"].column {
-    width: 25% !important;
-  }
-
-  .ui.grid > .row > [class*="five wide large screen"].column,
-  .ui.grid > .column.row > [class*="five wide large screen"].column,
-  .ui.grid > [class*="five wide large screen"].column,
-  .ui.column.grid > [class*="five wide large screen"].column {
-    width: 31.25% !important;
-  }
-
-  .ui.grid > .row > [class*="six wide large screen"].column,
-  .ui.grid > .column.row > [class*="six wide large screen"].column,
-  .ui.grid > [class*="six wide large screen"].column,
-  .ui.column.grid > [class*="six wide large screen"].column {
-    width: 37.5% !important;
-  }
-
-  .ui.grid > .row > [class*="seven wide large screen"].column,
-  .ui.grid > .column.row > [class*="seven wide large screen"].column,
-  .ui.grid > [class*="seven wide large screen"].column,
-  .ui.column.grid > [class*="seven wide large screen"].column {
-    width: 43.75% !important;
-  }
-
-  .ui.grid > .row > [class*="eight wide large screen"].column,
-  .ui.grid > .column.row > [class*="eight wide large screen"].column,
-  .ui.grid > [class*="eight wide large screen"].column,
-  .ui.column.grid > [class*="eight wide large screen"].column {
-    width: 50% !important;
-  }
-
-  .ui.grid > .row > [class*="nine wide large screen"].column,
-  .ui.grid > .column.row > [class*="nine wide large screen"].column,
-  .ui.grid > [class*="nine wide large screen"].column,
-  .ui.column.grid > [class*="nine wide large screen"].column {
-    width: 56.25% !important;
-  }
-
-  .ui.grid > .row > [class*="ten wide large screen"].column,
-  .ui.grid > .column.row > [class*="ten wide large screen"].column,
-  .ui.grid > [class*="ten wide large screen"].column,
-  .ui.column.grid > [class*="ten wide large screen"].column {
-    width: 62.5% !important;
-  }
-
-  .ui.grid > .row > [class*="eleven wide large screen"].column,
-  .ui.grid > .column.row > [class*="eleven wide large screen"].column,
-  .ui.grid > [class*="eleven wide large screen"].column,
-  .ui.column.grid > [class*="eleven wide large screen"].column {
-    width: 68.75% !important;
-  }
-
-  .ui.grid > .row > [class*="twelve wide large screen"].column,
-  .ui.grid > .column.row > [class*="twelve wide large screen"].column,
-  .ui.grid > [class*="twelve wide large screen"].column,
-  .ui.column.grid > [class*="twelve wide large screen"].column {
-    width: 75% !important;
-  }
-
-  .ui.grid > .row > [class*="thirteen wide large screen"].column,
-  .ui.grid > .column.row > [class*="thirteen wide large screen"].column,
-  .ui.grid > [class*="thirteen wide large screen"].column,
-  .ui.column.grid > [class*="thirteen wide large screen"].column {
-    width: 81.25% !important;
-  }
-
-  .ui.grid > .row > [class*="fourteen wide large screen"].column,
-  .ui.grid > .column.row > [class*="fourteen wide large screen"].column,
-  .ui.grid > [class*="fourteen wide large screen"].column,
-  .ui.column.grid > [class*="fourteen wide large screen"].column {
-    width: 87.5% !important;
-  }
-
-  .ui.grid > .row > [class*="fifteen wide large screen"].column,
-  .ui.grid > .column.row > [class*="fifteen wide large screen"].column,
-  .ui.grid > [class*="fifteen wide large screen"].column,
-  .ui.column.grid > [class*="fifteen wide large screen"].column {
-    width: 93.75% !important;
-  }
-
-  .ui.grid > .row > [class*="sixteen wide large screen"].column,
-  .ui.grid > .column.row > [class*="sixteen wide large screen"].column,
-  .ui.grid > [class*="sixteen wide large screen"].column,
-  .ui.column.grid > [class*="sixteen wide large screen"].column {
-    width: 100% !important;
-  }
-}
-
-/* Widescreen Sizing Combinations */
-
-@media only screen and (min-width: 1920px) {
-  .ui.grid > .row > [class*="one wide widescreen"].column,
-  .ui.grid > .column.row > [class*="one wide widescreen"].column,
-  .ui.grid > [class*="one wide widescreen"].column,
-  .ui.column.grid > [class*="one wide widescreen"].column {
-    width: 6.25% !important;
-  }
-
-  .ui.grid > .row > [class*="two wide widescreen"].column,
-  .ui.grid > .column.row > [class*="two wide widescreen"].column,
-  .ui.grid > [class*="two wide widescreen"].column,
-  .ui.column.grid > [class*="two wide widescreen"].column {
-    width: 12.5% !important;
-  }
-
-  .ui.grid > .row > [class*="three wide widescreen"].column,
-  .ui.grid > .column.row > [class*="three wide widescreen"].column,
-  .ui.grid > [class*="three wide widescreen"].column,
-  .ui.column.grid > [class*="three wide widescreen"].column {
-    width: 18.75% !important;
-  }
-
-  .ui.grid > .row > [class*="four wide widescreen"].column,
-  .ui.grid > .column.row > [class*="four wide widescreen"].column,
-  .ui.grid > [class*="four wide widescreen"].column,
-  .ui.column.grid > [class*="four wide widescreen"].column {
-    width: 25% !important;
-  }
-
-  .ui.grid > .row > [class*="five wide widescreen"].column,
-  .ui.grid > .column.row > [class*="five wide widescreen"].column,
-  .ui.grid > [class*="five wide widescreen"].column,
-  .ui.column.grid > [class*="five wide widescreen"].column {
-    width: 31.25% !important;
-  }
-
-  .ui.grid > .row > [class*="six wide widescreen"].column,
-  .ui.grid > .column.row > [class*="six wide widescreen"].column,
-  .ui.grid > [class*="six wide widescreen"].column,
-  .ui.column.grid > [class*="six wide widescreen"].column {
-    width: 37.5% !important;
-  }
-
-  .ui.grid > .row > [class*="seven wide widescreen"].column,
-  .ui.grid > .column.row > [class*="seven wide widescreen"].column,
-  .ui.grid > [class*="seven wide widescreen"].column,
-  .ui.column.grid > [class*="seven wide widescreen"].column {
-    width: 43.75% !important;
-  }
-
-  .ui.grid > .row > [class*="eight wide widescreen"].column,
-  .ui.grid > .column.row > [class*="eight wide widescreen"].column,
-  .ui.grid > [class*="eight wide widescreen"].column,
-  .ui.column.grid > [class*="eight wide widescreen"].column {
-    width: 50% !important;
-  }
-
-  .ui.grid > .row > [class*="nine wide widescreen"].column,
-  .ui.grid > .column.row > [class*="nine wide widescreen"].column,
-  .ui.grid > [class*="nine wide widescreen"].column,
-  .ui.column.grid > [class*="nine wide widescreen"].column {
-    width: 56.25% !important;
-  }
-
-  .ui.grid > .row > [class*="ten wide widescreen"].column,
-  .ui.grid > .column.row > [class*="ten wide widescreen"].column,
-  .ui.grid > [class*="ten wide widescreen"].column,
-  .ui.column.grid > [class*="ten wide widescreen"].column {
-    width: 62.5% !important;
-  }
-
-  .ui.grid > .row > [class*="eleven wide widescreen"].column,
-  .ui.grid > .column.row > [class*="eleven wide widescreen"].column,
-  .ui.grid > [class*="eleven wide widescreen"].column,
-  .ui.column.grid > [class*="eleven wide widescreen"].column {
-    width: 68.75% !important;
-  }
-
-  .ui.grid > .row > [class*="twelve wide widescreen"].column,
-  .ui.grid > .column.row > [class*="twelve wide widescreen"].column,
-  .ui.grid > [class*="twelve wide widescreen"].column,
-  .ui.column.grid > [class*="twelve wide widescreen"].column {
-    width: 75% !important;
-  }
-
-  .ui.grid > .row > [class*="thirteen wide widescreen"].column,
-  .ui.grid > .column.row > [class*="thirteen wide widescreen"].column,
-  .ui.grid > [class*="thirteen wide widescreen"].column,
-  .ui.column.grid > [class*="thirteen wide widescreen"].column {
-    width: 81.25% !important;
-  }
-
-  .ui.grid > .row > [class*="fourteen wide widescreen"].column,
-  .ui.grid > .column.row > [class*="fourteen wide widescreen"].column,
-  .ui.grid > [class*="fourteen wide widescreen"].column,
-  .ui.column.grid > [class*="fourteen wide widescreen"].column {
-    width: 87.5% !important;
-  }
-
-  .ui.grid > .row > [class*="fifteen wide widescreen"].column,
-  .ui.grid > .column.row > [class*="fifteen wide widescreen"].column,
-  .ui.grid > [class*="fifteen wide widescreen"].column,
-  .ui.column.grid > [class*="fifteen wide widescreen"].column {
-    width: 93.75% !important;
-  }
-
-  .ui.grid > .row > [class*="sixteen wide widescreen"].column,
-  .ui.grid > .column.row > [class*="sixteen wide widescreen"].column,
-  .ui.grid > [class*="sixteen wide widescreen"].column,
-  .ui.column.grid > [class*="sixteen wide widescreen"].column {
-    width: 100% !important;
-  }
-}
-
-/*----------------------
-          Centered
-  -----------------------*/
-
-.ui.centered.grid,
-.ui.centered.grid > .row,
-.ui.grid > .centered.row {
-  text-align: center;
-  justify-content: center;
-}
-
-.ui.centered.grid > .column:not(.aligned):not(.justified):not(.row),
-.ui.centered.grid > .row > .column:not(.aligned):not(.justified),
-.ui.grid .centered.row > .column:not(.aligned):not(.justified) {
-  text-align: left;
-}
-
-.ui.grid > .centered.column,
-.ui.grid > .row > .centered.column {
-  display: block;
-  margin-left: auto;
-  margin-right: auto;
-}
-
-/*----------------------
-          Relaxed
-  -----------------------*/
-
-.ui.relaxed.grid > .column:not(.row),
-.ui.relaxed.grid > .row > .column,
-.ui.grid > .relaxed.row > .column {
-  padding-left: 1.5rem;
-  padding-right: 1.5rem;
-}
-
-.ui[class*="very relaxed"].grid > .column:not(.row),
-.ui[class*="very relaxed"].grid > .row > .column,
-.ui.grid > [class*="very relaxed"].row > .column {
-  padding-left: 2.5rem;
-  padding-right: 2.5rem;
-}
-
-/* Coupling with UI Divider */
-
-.ui.relaxed.grid .row + .ui.divider,
-.ui.grid .relaxed.row + .ui.divider {
-  margin-left: 1.5rem;
-  margin-right: 1.5rem;
-}
-
-.ui[class*="very relaxed"].grid .row + .ui.divider,
-.ui.grid [class*="very relaxed"].row + .ui.divider {
-  margin-left: 2.5rem;
-  margin-right: 2.5rem;
-}
-
-/*----------------------
-          Padded
-  -----------------------*/
-
-.ui.padded.grid:not(.vertically):not(.horizontally) {
-  margin: 0 !important;
-}
-
-[class*="horizontally padded"].ui.grid {
-  margin-left: 0 !important;
-  margin-right: 0 !important;
-}
-
-[class*="vertically padded"].ui.grid {
-  margin-top: 0 !important;
-  margin-bottom: 0 !important;
-}
-
-/*----------------------
-         "Floated"
-  -----------------------*/
-
-.ui.grid [class*="left floated"].column {
-  margin-right: auto;
-}
-
-.ui.grid [class*="right floated"].column {
-  margin-left: auto;
-}
-
-/*----------------------
-          Divided
-  -----------------------*/
-
-.ui.divided.grid:not([class*="vertically divided"]) > .column:not(.row),
-.ui.divided.grid:not([class*="vertically divided"]) > .row > .column {
-  box-shadow: -1px 0 0 0 rgba(34, 36, 38, 0.15);
-}
-
-/* Swap from padding to margin on columns to have dividers align */
-
-.ui[class*="vertically divided"].grid > .column:not(.row),
-.ui[class*="vertically divided"].grid > .row > .column {
-  margin-top: 1rem;
-  margin-bottom: 1rem;
-  padding-top: 0;
-  padding-bottom: 0;
-}
-
-.ui[class*="vertically divided"].grid > .row {
-  margin-top: 0;
-  margin-bottom: 0;
-}
-
-/* No divider on first column on row */
-
-.ui.divided.grid:not([class*="vertically divided"]) > .column:first-child,
-.ui.divided.grid:not([class*="vertically divided"]) > .row > .column:first-child {
-  box-shadow: none;
-}
-
-/* No space on top of first row */
-
-.ui[class*="vertically divided"].grid > .row:first-child > .column {
-  margin-top: 0;
-}
-
-/* Divided Row */
-
-.ui.grid > .divided.row > .column {
-  box-shadow: -1px 0 0 0 rgba(34, 36, 38, 0.15);
-}
-
-.ui.grid > .divided.row > .column:first-child {
-  box-shadow: none;
-}
-
-/* Vertically Divided */
-
-.ui[class*="vertically divided"].grid > .row {
-  position: relative;
-}
-
-.ui[class*="vertically divided"].grid > .row:before {
-  position: absolute;
-  content: "";
-  top: 0;
-  left: 0;
-  width: calc(100% - 2rem);
-  height: 1px;
-  margin: 0 1rem;
-  box-shadow: 0 -1px 0 0 rgba(34, 36, 38, 0.15);
-}
-
-/* Padded Horizontally Divided */
-
-[class*="horizontally padded"].ui.divided.grid,
-.ui.padded.divided.grid:not(.vertically):not(.horizontally) {
-  width: 100%;
-}
-
-/* First Row Vertically Divided */
-
-.ui[class*="vertically divided"].grid > .row:first-child:before {
-  box-shadow: none;
-}
-
-/* Relaxed */
-
-.ui.relaxed[class*="vertically divided"].grid > .row:before {
-  margin-left: 1.5rem;
-  margin-right: 1.5rem;
-  width: calc(100% - 3rem);
-}
-
-.ui[class*="very relaxed"][class*="vertically divided"].grid > .row:before {
-  margin-left: 2.5rem;
-  margin-right: 2.5rem;
-  width: calc(100% - 5rem);
-}
-
-/*----------------------
-           Celled
-  -----------------------*/
-
-.ui.celled.grid {
-  width: 100%;
-  margin: 1em 0;
-  box-shadow: 0 0 0 1px #D4D4D5;
-}
-
-.ui.celled.grid > .row {
-  width: 100% !important;
-  margin: 0;
-  padding: 0;
-  box-shadow: 0 -1px 0 0 #D4D4D5;
-}
-
-.ui.celled.grid > .column:not(.row),
-.ui.celled.grid > .row > .column {
-  box-shadow: -1px 0 0 0 #D4D4D5;
-}
-
-.ui.celled.grid > .column:first-child,
-.ui.celled.grid > .row > .column:first-child {
-  box-shadow: none;
-}
-
-.ui.celled.grid > .column:not(.row),
-.ui.celled.grid > .row > .column {
-  padding: 1em;
-}
-
-.ui.relaxed.celled.grid > .column:not(.row),
-.ui.relaxed.celled.grid > .row > .column {
-  padding: 1.5em;
-}
-
-.ui[class*="very relaxed"].celled.grid > .column:not(.row),
-.ui[class*="very relaxed"].celled.grid > .row > .column {
-  padding: 2em;
-}
-
-/* Internally Celled */
-
-.ui[class*="internally celled"].grid {
-  box-shadow: none;
-  margin: 0;
-}
-
-.ui[class*="internally celled"].grid > .row:first-child {
-  box-shadow: none;
-}
-
-.ui[class*="internally celled"].grid > .row > .column:first-child {
-  box-shadow: none;
-}
-
-/*----------------------
-     Vertically Aligned
-  -----------------------*/
-
-/* Top Aligned */
-
-.ui[class*="top aligned"].grid > .column:not(.row),
-.ui[class*="top aligned"].grid > .row > .column,
-.ui.grid > [class*="top aligned"].row > .column,
-.ui.grid > [class*="top aligned"].column:not(.row),
-.ui.grid > .row > [class*="top aligned"].column {
-  flex-direction: column;
-  vertical-align: top;
-  align-self: flex-start !important;
-}
-
-/* Middle Aligned */
-
-.ui[class*="middle aligned"].grid > .column:not(.row),
-.ui[class*="middle aligned"].grid > .row > .column,
-.ui.grid > [class*="middle aligned"].row > .column,
-.ui.grid > [class*="middle aligned"].column:not(.row),
-.ui.grid > .row > [class*="middle aligned"].column {
-  flex-direction: column;
-  vertical-align: middle;
-  align-self: center !important;
-}
-
-/* Bottom Aligned */
-
-.ui[class*="bottom aligned"].grid > .column:not(.row),
-.ui[class*="bottom aligned"].grid > .row > .column,
-.ui.grid > [class*="bottom aligned"].row > .column,
-.ui.grid > [class*="bottom aligned"].column:not(.row),
-.ui.grid > .row > [class*="bottom aligned"].column {
-  flex-direction: column;
-  vertical-align: bottom;
-  align-self: flex-end !important;
-}
-
-/* Stretched */
-
-.ui.stretched.grid > .row > .column,
-.ui.stretched.grid > .column,
-.ui.grid > .stretched.row > .column,
-.ui.grid > .stretched.column:not(.row),
-.ui.grid > .row > .stretched.column {
-  display: inline-flex !important;
-  align-self: stretch;
-  flex-direction: column;
-}
-
-.ui.stretched.grid > .row > .column > *,
-.ui.stretched.grid > .column > *,
-.ui.grid > .stretched.row > .column > *,
-.ui.grid > .stretched.column:not(.row) > *,
-.ui.grid > .row > .stretched.column > * {
-  flex-grow: 1;
-}
-
-/*----------------------
-    Horizontally Centered
-  -----------------------*/
-
-/* Left Aligned */
-
-.ui[class*="left aligned"].grid > .column,
-.ui[class*="left aligned"].grid > .row > .column,
-.ui.grid > [class*="left aligned"].row > .column,
-.ui.grid > [class*="left aligned"].column.column,
-.ui.grid > .row > [class*="left aligned"].column.column {
-  text-align: left;
-  align-self: inherit;
-}
-
-/* Center Aligned */
-
-.ui[class*="center aligned"].grid > .column,
-.ui[class*="center aligned"].grid > .row > .column,
-.ui.grid > [class*="center aligned"].row > .column,
-.ui.grid > [class*="center aligned"].column.column,
-.ui.grid > .row > [class*="center aligned"].column.column {
-  text-align: center;
-  align-self: inherit;
-}
-
-.ui[class*="center aligned"].grid {
-  justify-content: center;
-}
-
-/* Right Aligned */
-
-.ui[class*="right aligned"].grid > .column,
-.ui[class*="right aligned"].grid > .row > .column,
-.ui.grid > [class*="right aligned"].row > .column,
-.ui.grid > [class*="right aligned"].column.column,
-.ui.grid > .row > [class*="right aligned"].column.column {
-  text-align: right;
-  align-self: inherit;
-}
-
-/* Justified */
-
-.ui.justified.grid > .column,
-.ui.justified.grid > .row > .column,
-.ui.grid > .justified.row > .column,
-.ui.grid > .justified.column.column,
-.ui.grid > .row > .justified.column.column {
-  text-align: justify;
-  -webkit-hyphens: auto;
-  hyphens: auto;
-}
-
-/*----------------------
-         Colored
------------------------*/
-
-.ui.grid > .primary.row,
-.ui.grid > .primary.column,
-.ui.grid > .row > .primary.column {
-  background-color: #2185D0;
-  color: #FFFFFF;
-}
-
-.ui.grid > .secondary.row,
-.ui.grid > .secondary.column,
-.ui.grid > .row > .secondary.column {
-  background-color: #1B1C1D;
-  color: #FFFFFF;
-}
-
-.ui.grid > .red.row,
-.ui.grid > .red.column,
-.ui.grid > .row > .red.column {
-  background-color: #DB2828;
-  color: #FFFFFF;
-}
-
-.ui.grid > .orange.row,
-.ui.grid > .orange.column,
-.ui.grid > .row > .orange.column {
-  background-color: #F2711C;
-  color: #FFFFFF;
-}
-
-.ui.grid > .yellow.row,
-.ui.grid > .yellow.column,
-.ui.grid > .row > .yellow.column {
-  background-color: #FBBD08;
-  color: #FFFFFF;
-}
-
-.ui.grid > .olive.row,
-.ui.grid > .olive.column,
-.ui.grid > .row > .olive.column {
-  background-color: #B5CC18;
-  color: #FFFFFF;
-}
-
-.ui.grid > .green.row,
-.ui.grid > .green.column,
-.ui.grid > .row > .green.column {
-  background-color: #21BA45;
-  color: #FFFFFF;
-}
-
-.ui.grid > .teal.row,
-.ui.grid > .teal.column,
-.ui.grid > .row > .teal.column {
-  background-color: #00B5AD;
-  color: #FFFFFF;
-}
-
-.ui.grid > .blue.row,
-.ui.grid > .blue.column,
-.ui.grid > .row > .blue.column {
-  background-color: #2185D0;
-  color: #FFFFFF;
-}
-
-.ui.grid > .violet.row,
-.ui.grid > .violet.column,
-.ui.grid > .row > .violet.column {
-  background-color: #6435C9;
-  color: #FFFFFF;
-}
-
-.ui.grid > .purple.row,
-.ui.grid > .purple.column,
-.ui.grid > .row > .purple.column {
-  background-color: #A333C8;
-  color: #FFFFFF;
-}
-
-.ui.grid > .pink.row,
-.ui.grid > .pink.column,
-.ui.grid > .row > .pink.column {
-  background-color: #E03997;
-  color: #FFFFFF;
-}
-
-.ui.grid > .brown.row,
-.ui.grid > .brown.column,
-.ui.grid > .row > .brown.column {
-  background-color: #A5673F;
-  color: #FFFFFF;
-}
-
-.ui.grid > .grey.row,
-.ui.grid > .grey.column,
-.ui.grid > .row > .grey.column {
-  background-color: #767676;
-  color: #FFFFFF;
-}
-
-.ui.grid > .black.row,
-.ui.grid > .black.column,
-.ui.grid > .row > .black.column {
-  background-color: #1B1C1D;
-  color: #FFFFFF;
-}
-
-/*----------------------
-      Equal Width
------------------------*/
-
-.ui[class*="equal width"].grid > .column:not(.row),
-.ui[class*="equal width"].grid > .row > .column,
-.ui.grid > [class*="equal width"].row > .column {
-  display: inline-block;
-  flex-grow: 1;
-}
-
-.ui[class*="equal width"].grid > .wide.column,
-.ui[class*="equal width"].grid > .row > .wide.column,
-.ui.grid > [class*="equal width"].row > .wide.column {
-  flex-grow: 0;
-}
-
-/*----------------------
-          Reverse
-  -----------------------*/
-
-/* Mobile */
-
-@media only screen and (max-width: 767.98px) {
-  .ui[class*="mobile reversed"].grid,
-  .ui[class*="mobile reversed"].grid > .row,
-  .ui.grid > [class*="mobile reversed"].row {
-    flex-direction: row-reverse;
-  }
-
-  .ui[class*="mobile vertically reversed"].grid,
-  .ui.stackable[class*="mobile reversed"] {
-    flex-direction: column-reverse;
-  }
-
-  /* Divided Reversed */
-
-  .ui[class*="mobile reversed"].divided.grid:not([class*="vertically divided"]) > .column:first-child,
-  .ui[class*="mobile reversed"].divided.grid:not([class*="vertically divided"]) > .row > .column:first-child {
-    box-shadow: -1px 0 0 0 rgba(34, 36, 38, 0.15);
-  }
-
-  .ui[class*="mobile reversed"].divided.grid:not([class*="vertically divided"]) > .column:last-child,
-  .ui[class*="mobile reversed"].divided.grid:not([class*="vertically divided"]) > .row > .column:last-child {
-    box-shadow: none;
-  }
-
-  /* Vertically Divided Reversed */
-
-  .ui.grid[class*="vertically divided"][class*="mobile vertically reversed"] > .row:first-child:before {
-    box-shadow: 0 -1px 0 0 rgba(34, 36, 38, 0.15);
-  }
-
-  .ui.grid[class*="vertically divided"][class*="mobile vertically reversed"] > .row:last-child:before {
-    box-shadow: none;
-  }
-
-  /* Celled Reversed */
-
-  .ui[class*="mobile reversed"].celled.grid > .row > .column:first-child {
-    box-shadow: -1px 0 0 0 #D4D4D5;
-  }
-
-  .ui[class*="mobile reversed"].celled.grid > .row > .column:last-child {
-    box-shadow: none;
-  }
-}
-
-/* Tablet */
-
-@media only screen and (min-width: 768px) and (max-width: 991.98px) {
-  .ui[class*="tablet reversed"].grid,
-  .ui[class*="tablet reversed"].grid > .row,
-  .ui.grid > [class*="tablet reversed"].row {
-    flex-direction: row-reverse;
-  }
-
-  .ui[class*="tablet vertically reversed"].grid {
-    flex-direction: column-reverse;
-  }
-
-  /* Divided Reversed */
-
-  .ui[class*="tablet reversed"].divided.grid:not([class*="vertically divided"]) > .column:first-child,
-  .ui[class*="tablet reversed"].divided.grid:not([class*="vertically divided"]) > .row > .column:first-child {
-    box-shadow: -1px 0 0 0 rgba(34, 36, 38, 0.15);
-  }
-
-  .ui[class*="tablet reversed"].divided.grid:not([class*="vertically divided"]) > .column:last-child,
-  .ui[class*="tablet reversed"].divided.grid:not([class*="vertically divided"]) > .row > .column:last-child {
-    box-shadow: none;
-  }
-
-  /* Vertically Divided Reversed */
-
-  .ui.grid[class*="vertically divided"][class*="tablet vertically reversed"] > .row:first-child:before {
-    box-shadow: 0 -1px 0 0 rgba(34, 36, 38, 0.15);
-  }
-
-  .ui.grid[class*="vertically divided"][class*="tablet vertically reversed"] > .row:last-child:before {
-    box-shadow: none;
-  }
-
-  /* Celled Reversed */
-
-  .ui[class*="tablet reversed"].celled.grid > .row > .column:first-child {
-    box-shadow: -1px 0 0 0 #D4D4D5;
-  }
-
-  .ui[class*="tablet reversed"].celled.grid > .row > .column:last-child {
-    box-shadow: none;
-  }
-}
-
-/* Computer */
-
-@media only screen and (min-width: 992px) {
-  .ui[class*="computer reversed"].grid,
-  .ui[class*="computer reversed"].grid > .row,
-  .ui.grid > [class*="computer reversed"].row {
-    flex-direction: row-reverse;
-  }
-
-  .ui[class*="computer vertically reversed"].grid {
-    flex-direction: column-reverse;
-  }
-
-  /* Divided Reversed */
-
-  .ui[class*="computer reversed"].divided.grid:not([class*="vertically divided"]) > .column:first-child,
-  .ui[class*="computer reversed"].divided.grid:not([class*="vertically divided"]) > .row > .column:first-child {
-    box-shadow: -1px 0 0 0 rgba(34, 36, 38, 0.15);
-  }
-
-  .ui[class*="computer reversed"].divided.grid:not([class*="vertically divided"]) > .column:last-child,
-  .ui[class*="computer reversed"].divided.grid:not([class*="vertically divided"]) > .row > .column:last-child {
-    box-shadow: none;
-  }
-
-  /* Vertically Divided Reversed */
-
-  .ui.grid[class*="vertically divided"][class*="computer vertically reversed"] > .row:first-child:before {
-    box-shadow: 0 -1px 0 0 rgba(34, 36, 38, 0.15);
-  }
-
-  .ui.grid[class*="vertically divided"][class*="computer vertically reversed"] > .row:last-child:before {
-    box-shadow: none;
-  }
-
-  /* Celled Reversed */
-
-  .ui[class*="computer reversed"].celled.grid > .row > .column:first-child {
-    box-shadow: -1px 0 0 0 #D4D4D5;
-  }
-
-  .ui[class*="computer reversed"].celled.grid > .row > .column:last-child {
-    box-shadow: none;
-  }
-}
-
-/*-------------------
-        Stackable
-  --------------------*/
-
-@media only screen and (max-width: 767.98px) {
-  .ui.stackable.grid {
-    width: auto;
-    margin-left: 0 !important;
-    margin-right: 0 !important;
-  }
-
-  .ui.stackable.grid > .row > .wide.column,
-  .ui.stackable.grid > .wide.column,
-  .ui.stackable.grid > .column.grid > .column,
-  .ui.stackable.grid > .column.row > .column,
-  .ui.stackable.grid > .row > .column,
-  .ui.stackable.grid > .column:not(.row),
-  .ui.grid > .stackable.stackable.stackable.row > .column {
-    width: 100% !important;
-    margin: 0 0 !important;
-    box-shadow: none !important;
-    padding: 1rem 1rem;
-  }
-
-  .ui.stackable.grid:not(.vertically) > .row {
-    margin: 0;
-    padding: 0;
-  }
-
-  /* Coupling */
-
-  .ui.container > .ui.stackable.grid > .column,
-  .ui.container > .ui.stackable.grid > .row > .column {
-    padding-left: 0 !important;
-    padding-right: 0 !important;
-  }
-
-  /* Don't pad inside segment or nested grid */
-
-  .ui.grid .ui.stackable.grid,
-  .ui.segment:not(.vertical) .ui.stackable.page.grid {
-    margin-left: -1rem !important;
-    margin-right: -1rem !important;
-  }
-
-  /* Divided Stackable */
-
-  .ui.stackable.divided.grid > .row:first-child > .column:first-child,
-  .ui.stackable.celled.grid > .row:first-child > .column:first-child,
-  .ui.stackable.divided.grid > .column:not(.row):first-child,
-  .ui.stackable.celled.grid > .column:not(.row):first-child {
-    border-top: none !important;
-  }
-
-  .ui.stackable.celled.grid > .column:not(.row),
-  .ui.stackable.divided:not(.vertically).grid > .column:not(.row),
-  .ui.stackable.celled.grid > .row > .column,
-  .ui.stackable.divided:not(.vertically).grid > .row > .column {
-    border-top: 1px solid rgba(34, 36, 38, 0.15);
-    box-shadow: none !important;
-    padding-top: 2rem !important;
-    padding-bottom: 2rem !important;
-  }
-
-  .ui.stackable.celled.grid > .row {
-    box-shadow: none !important;
-  }
-
-  .ui.stackable.divided:not(.vertically).grid > .column:not(.row),
-  .ui.stackable.divided:not(.vertically).grid > .row > .column {
-    padding-left: 0 !important;
-    padding-right: 0 !important;
-  }
-}
-
-/*----------------------
-     Only (Device)
------------------------*/
-
-/* These include arbitrary class repetitions for forced specificity */
-
-/* Mobile Only Hide */
-
-@media only screen and (max-width: 767.98px) {
-  .ui[class*="tablet only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="tablet only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="tablet only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="tablet only"].column:not(.mobile) {
-    display: none !important;
-  }
-
-  .ui[class*="computer only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="computer only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="computer only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="computer only"].column:not(.mobile) {
-    display: none !important;
-  }
-
-  .ui[class*="large screen only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="large screen only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="large screen only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="large screen only"].column:not(.mobile) {
-    display: none !important;
-  }
-
-  .ui[class*="widescreen only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="widescreen only"].column:not(.mobile) {
-    display: none !important;
-  }
-}
-
-/* Tablet Only Hide */
-
-@media only screen and (min-width: 768px) and (max-width: 991.98px) {
-  .ui[class*="mobile only"].grid.grid.grid:not(.tablet),
-  .ui.grid.grid.grid > [class*="mobile only"].row:not(.tablet),
-  .ui.grid.grid.grid > [class*="mobile only"].column:not(.tablet),
-  .ui.grid.grid.grid > .row > [class*="mobile only"].column:not(.tablet) {
-    display: none !important;
-  }
-
-  .ui[class*="computer only"].grid.grid.grid:not(.tablet),
-  .ui.grid.grid.grid > [class*="computer only"].row:not(.tablet),
-  .ui.grid.grid.grid > [class*="computer only"].column:not(.tablet),
-  .ui.grid.grid.grid > .row > [class*="computer only"].column:not(.tablet) {
-    display: none !important;
-  }
-
-  .ui[class*="large screen only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="large screen only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="large screen only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="large screen only"].column:not(.mobile) {
-    display: none !important;
-  }
-
-  .ui[class*="widescreen only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="widescreen only"].column:not(.mobile) {
-    display: none !important;
-  }
-}
-
-/* Computer Only Hide */
-
-@media only screen and (min-width: 992px) and (max-width: 1199.98px) {
-  .ui[class*="mobile only"].grid.grid.grid:not(.computer),
-  .ui.grid.grid.grid > [class*="mobile only"].row:not(.computer),
-  .ui.grid.grid.grid > [class*="mobile only"].column:not(.computer),
-  .ui.grid.grid.grid > .row > [class*="mobile only"].column:not(.computer) {
-    display: none !important;
-  }
-
-  .ui[class*="tablet only"].grid.grid.grid:not(.computer),
-  .ui.grid.grid.grid > [class*="tablet only"].row:not(.computer),
-  .ui.grid.grid.grid > [class*="tablet only"].column:not(.computer),
-  .ui.grid.grid.grid > .row > [class*="tablet only"].column:not(.computer) {
-    display: none !important;
-  }
-
-  .ui[class*="large screen only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="large screen only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="large screen only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="large screen only"].column:not(.mobile) {
-    display: none !important;
-  }
-
-  .ui[class*="widescreen only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="widescreen only"].column:not(.mobile) {
-    display: none !important;
-  }
-}
-
-/* Large Screen Only Hide */
-
-@media only screen and (min-width: 1200px) and (max-width: 1919.98px) {
-  .ui[class*="mobile only"].grid.grid.grid:not(.computer),
-  .ui.grid.grid.grid > [class*="mobile only"].row:not(.computer),
-  .ui.grid.grid.grid > [class*="mobile only"].column:not(.computer),
-  .ui.grid.grid.grid > .row > [class*="mobile only"].column:not(.computer) {
-    display: none !important;
-  }
-
-  .ui[class*="tablet only"].grid.grid.grid:not(.computer),
-  .ui.grid.grid.grid > [class*="tablet only"].row:not(.computer),
-  .ui.grid.grid.grid > [class*="tablet only"].column:not(.computer),
-  .ui.grid.grid.grid > .row > [class*="tablet only"].column:not(.computer) {
-    display: none !important;
-  }
-
-  .ui[class*="widescreen only"].grid.grid.grid:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].row:not(.mobile),
-  .ui.grid.grid.grid > [class*="widescreen only"].column:not(.mobile),
-  .ui.grid.grid.grid > .row > [class*="widescreen only"].column:not(.mobile) {
-    display: none !important;
-  }
-}
-
-/* Widescreen Only Hide */
-
-@media only screen and (min-width: 1920px) {
-  .ui[class*="mobile only"].grid.grid.grid:not(.computer),
-  .ui.grid.grid.grid > [class*="mobile only"].row:not(.computer),
-  .ui.grid.grid.grid > [class*="mobile only"].column:not(.computer),
-  .ui.grid.grid.grid > .row > [class*="mobile only"].column:not(.computer) {
-    display: none !important;
-  }
-
-  .ui[class*="tablet only"].grid.grid.grid:not(.computer),
-  .ui.grid.grid.grid > [class*="tablet only"].row:not(.computer),
-  .ui.grid.grid.grid > [class*="tablet only"].column:not(.computer),
-  .ui.grid.grid.grid > .row > [class*="tablet only"].column:not(.computer) {
-    display: none !important;
-  }
-}
-
-/*-----------------
-        Compact
-  -----------------*/
-
-.ui.ui.ui.compact.grid > .column:not(.row),
-.ui.ui.ui.compact.grid > .row > .column {
-  padding-left: 0.5rem;
-  padding-right: 0.5rem;
-}
-
-.ui.ui.ui.compact.grid > * {
-  padding-left: 0.5rem;
-  padding-right: 0.5rem;
-}
-
-/* Row */
-
-.ui.ui.ui.compact.grid > .row {
-  padding-top: 0.5rem;
-  padding-bottom: 0.5rem;
-}
-
-/* Columns */
-
-.ui.ui.ui.compact.grid > .column:not(.row) {
-  padding-top: 0.5rem;
-  padding-bottom: 0.5rem;
-}
-
-/* Relaxed + Celled */
-
-.ui.compact.relaxed.celled.grid > .column:not(.row),
-.ui.compact.relaxed.celled.grid > .row > .column {
-  padding: 0.75em;
-}
-
-.ui.compact[class*="very relaxed"].celled.grid > .column:not(.row),
-.ui.compact[class*="very relaxed"].celled.grid > .row > .column {
-  padding: 1em;
-}
-
-/*-----------------
-      Very compact
-  -----------------*/
-
-.ui.ui.ui[class*="very compact"].grid > .column:not(.row),
-.ui.ui.ui[class*="very compact"].grid > .row > .column {
-  padding-left: 0.25rem;
-  padding-right: 0.25rem;
-}
-
-.ui.ui.ui[class*="very compact"].grid > * {
-  padding-left: 0.25rem;
-  padding-right: 0.25rem;
-}
-
-/* Row */
-
-.ui.ui.ui[class*="very compact"].grid > .row {
-  padding-top: 0.25rem;
-  padding-bottom: 0.25rem;
-  padding-left: 0.75rem;
-  padding-right: 0.75rem;
-}
-
-/* Columns */
-
-.ui.ui.ui[class*="very compact"].grid > .column:not(.row) {
-  padding-top: 0.25rem;
-  padding-bottom: 0.25rem;
-}
-
-/* Relaxed + Celled */
-
-.ui[class*="very compact"].relaxed.celled.grid > .column:not(.row),
-.ui[class*="very compact"].relaxed.celled.grid > .row > .column {
-  padding: 0.375em;
-}
-
-.ui[class*="very compact"][class*="very relaxed"].celled.grid > .column:not(.row),
-.ui[class*="very compact"][class*="very relaxed"].celled.grid > .row > .column {
-  padding: 0.5em;
-}
-
-/*******************************
-         Theme Overrides
-*******************************/
-
 /*******************************
          Site Overrides
 *******************************/
@@ -16955,183 +14952,6 @@ Floated Menu / Item
          Theme Overrides
 *******************************/
 
-/*******************************
-         Site Overrides
-*******************************/
-/*!
- * # Fomantic-UI - Site
- * http://github.com/fomantic/Fomantic-UI/
- *
- *
- * Released under the MIT license
- * http://opensource.org/licenses/MIT
- *
- */
-
-/*******************************
-             Page
-*******************************/
-
-html,
-body {
-  height: 100%;
-}
-
-html {
-  font-size: 14px;
-}
-
-body {
-  margin: 0;
-  padding: 0;
-  overflow-x: visible;
-  min-width: 320px;
-  background: #FFFFFF;
-  font-family: var(--fonts-regular);
-  font-size: 14px;
-  line-height: 1.4285em;
-  color: rgba(0, 0, 0, 0.87);
-}
-
-/*******************************
-             Headers
-*******************************/
-
-h1,
-h2,
-h3,
-h4,
-h5 {
-  font-family: var(--fonts-regular);
-  line-height: 1.28571429em;
-  margin: calc(2rem - 0.1428571428571429em) 0 1rem;
-  font-weight: 500;
-  padding: 0;
-}
-
-h1 {
-  min-height: 1rem;
-  font-size: 2rem;
-}
-
-h2 {
-  font-size: 1.71428571rem;
-}
-
-h3 {
-  font-size: 1.28571429rem;
-}
-
-h4 {
-  font-size: 1.07142857rem;
-}
-
-h5 {
-  font-size: 1rem;
-}
-
-h1:first-child,
-h2:first-child,
-h3:first-child,
-h4:first-child,
-h5:first-child {
-  margin-top: 0;
-}
-
-h1:last-child,
-h2:last-child,
-h3:last-child,
-h4:last-child,
-h5:last-child {
-  margin-bottom: 0;
-}
-
-/*******************************
-             Text
-*******************************/
-
-p {
-  margin: 0 0 1em;
-  line-height: 1.4285em;
-}
-
-p:first-child {
-  margin-top: 0;
-}
-
-p:last-child {
-  margin-bottom: 0;
-}
-
-/*-------------------
-        Links
---------------------*/
-
-a {
-  color: #4183C4;
-  text-decoration: none;
-}
-
-a:hover {
-  color: #1e70bf;
-  text-decoration: underline;
-}
-
-/*******************************
-         Scrollbars
-*******************************/
-
-/*******************************
-          Highlighting
-*******************************/
-
-/* Site */
-
-::-webkit-selection {
-  background-color: #CCE2FF;
-  color: rgba(0, 0, 0, 0.87);
-}
-
-::-moz-selection {
-  background-color: #CCE2FF;
-  color: rgba(0, 0, 0, 0.87);
-}
-
-::selection {
-  background-color: #CCE2FF;
-  color: rgba(0, 0, 0, 0.87);
-}
-
-/* Form */
-
-textarea::-webkit-selection,
-input::-webkit-selection {
-  background-color: rgba(100, 100, 100, 0.4);
-  color: rgba(0, 0, 0, 0.87);
-}
-
-textarea::-moz-selection,
-input::-moz-selection {
-  background-color: rgba(100, 100, 100, 0.4);
-  color: rgba(0, 0, 0, 0.87);
-}
-
-textarea::-moz-selection,
-input::-moz-selection {
-  background-color: rgba(100, 100, 100, 0.4);
-  color: rgba(0, 0, 0, 0.87);
-}
-
-textarea::selection,
-input::selection {
-  background-color: rgba(100, 100, 100, 0.4);
-  color: rgba(0, 0, 0, 0.87);
-}
-
-/*******************************
-        Global Overrides
-*******************************/
-
 /*******************************
          Site Overrides
 *******************************/
diff --git a/web_src/fomantic/build/semantic.js b/web_src/fomantic/build/semantic.js
index 2a05d94d7..1199e9c82 100644
--- a/web_src/fomantic/build/semantic.js
+++ b/web_src/fomantic/build/semantic.js
@@ -11864,500 +11864,6 @@ $.fn.search.settings = {
   }
 };
 
-})( jQuery, window, document );
-
-/*!
- * # Fomantic-UI - Site
- * http://github.com/fomantic/Fomantic-UI/
- *
- *
- * Released under the MIT license
- * http://opensource.org/licenses/MIT
- *
- */
-
-;(function ($, window, document, undefined) {
-
-$.isFunction = $.isFunction || function(obj) {
-    return typeof obj === "function" && typeof obj.nodeType !== "number";
-};
-
-$.site = $.fn.site = function(parameters) {
-  var
-    time           = new Date().getTime(),
-    performance    = [],
-
-    query          = arguments[0],
-    methodInvoked  = (typeof query == 'string'),
-    queryArguments = [].slice.call(arguments, 1),
-
-    settings        = ( $.isPlainObject(parameters) )
-      ? $.extend(true, {}, $.site.settings, parameters)
-      : $.extend({}, $.site.settings),
-
-    namespace       = settings.namespace,
-    error           = settings.error,
-
-    moduleNamespace = 'module-' + namespace,
-
-    $document       = $(document),
-    $module         = $document,
-    element         = this,
-    instance        = $module.data(moduleNamespace),
-
-    module,
-    returnedValue
-  ;
-  module = {
-
-    initialize: function() {
-      module.instantiate();
-    },
-
-    instantiate: function() {
-      module.verbose('Storing instance of site', module);
-      instance = module;
-      $module
-        .data(moduleNamespace, module)
-      ;
-    },
-
-    normalize: function() {
-      module.fix.console();
-      module.fix.requestAnimationFrame();
-    },
-
-    fix: {
-      console: function() {
-        module.debug('Normalizing window.console');
-        if (console === undefined || console.log === undefined) {
-          module.verbose('Console not available, normalizing events');
-          module.disable.console();
-        }
-        if (typeof console.group == 'undefined' || typeof console.groupEnd == 'undefined' || typeof console.groupCollapsed == 'undefined') {
-          module.verbose('Console group not available, normalizing events');
-          window.console.group = function() {};
-          window.console.groupEnd = function() {};
-          window.console.groupCollapsed = function() {};
-        }
-        if (typeof console.markTimeline == 'undefined') {
-          module.verbose('Mark timeline not available, normalizing events');
-          window.console.markTimeline = function() {};
-        }
-      },
-      consoleClear: function() {
-        module.debug('Disabling programmatic console clearing');
-        window.console.clear = function() {};
-      },
-      requestAnimationFrame: function() {
-        module.debug('Normalizing requestAnimationFrame');
-        if(window.requestAnimationFrame === undefined) {
-          module.debug('RequestAnimationFrame not available, normalizing event');
-          window.requestAnimationFrame = window.requestAnimationFrame
-            || window.mozRequestAnimationFrame
-            || window.webkitRequestAnimationFrame
-            || window.msRequestAnimationFrame
-            || function(callback) { setTimeout(callback, 0); }
-          ;
-        }
-      }
-    },
-
-    moduleExists: function(name) {
-      return ($.fn[name] !== undefined && $.fn[name].settings !== undefined);
-    },
-
-    enabled: {
-      modules: function(modules) {
-        var
-          enabledModules = []
-        ;
-        modules = modules || settings.modules;
-        $.each(modules, function(index, name) {
-          if(module.moduleExists(name)) {
-            enabledModules.push(name);
-          }
-        });
-        return enabledModules;
-      }
-    },
-
-    disabled: {
-      modules: function(modules) {
-        var
-          disabledModules = []
-        ;
-        modules = modules || settings.modules;
-        $.each(modules, function(index, name) {
-          if(!module.moduleExists(name)) {
-            disabledModules.push(name);
-          }
-        });
-        return disabledModules;
-      }
-    },
-
-    change: {
-      setting: function(setting, value, modules, modifyExisting) {
-        modules = (typeof modules === 'string')
-          ? (modules === 'all')
-            ? settings.modules
-            : [modules]
-          : modules || settings.modules
-        ;
-        modifyExisting = (modifyExisting !== undefined)
-          ? modifyExisting
-          : true
-        ;
-        $.each(modules, function(index, name) {
-          var
-            namespace = (module.moduleExists(name))
-              ? $.fn[name].settings.namespace || false
-              : true,
-            $existingModules
-          ;
-          if(module.moduleExists(name)) {
-            module.verbose('Changing default setting', setting, value, name);
-            $.fn[name].settings[setting] = value;
-            if(modifyExisting && namespace) {
-              $existingModules = $(':data(module-' + namespace + ')');
-              if($existingModules.length > 0) {
-                module.verbose('Modifying existing settings', $existingModules);
-                $existingModules[name]('setting', setting, value);
-              }
-            }
-          }
-        });
-      },
-      settings: function(newSettings, modules, modifyExisting) {
-        modules = (typeof modules === 'string')
-          ? [modules]
-          : modules || settings.modules
-        ;
-        modifyExisting = (modifyExisting !== undefined)
-          ? modifyExisting
-          : true
-        ;
-        $.each(modules, function(index, name) {
-          var
-            $existingModules
-          ;
-          if(module.moduleExists(name)) {
-            module.verbose('Changing default setting', newSettings, name);
-            $.extend(true, $.fn[name].settings, newSettings);
-            if(modifyExisting && namespace) {
-              $existingModules = $(':data(module-' + namespace + ')');
-              if($existingModules.length > 0) {
-                module.verbose('Modifying existing settings', $existingModules);
-                $existingModules[name]('setting', newSettings);
-              }
-            }
-          }
-        });
-      }
-    },
-
-    enable: {
-      console: function() {
-        module.console(true);
-      },
-      debug: function(modules, modifyExisting) {
-        modules = modules || settings.modules;
-        module.debug('Enabling debug for modules', modules);
-        module.change.setting('debug', true, modules, modifyExisting);
-      },
-      verbose: function(modules, modifyExisting) {
-        modules = modules || settings.modules;
-        module.debug('Enabling verbose debug for modules', modules);
-        module.change.setting('verbose', true, modules, modifyExisting);
-      }
-    },
-    disable: {
-      console: function() {
-        module.console(false);
-      },
-      debug: function(modules, modifyExisting) {
-        modules = modules || settings.modules;
-        module.debug('Disabling debug for modules', modules);
-        module.change.setting('debug', false, modules, modifyExisting);
-      },
-      verbose: function(modules, modifyExisting) {
-        modules = modules || settings.modules;
-        module.debug('Disabling verbose debug for modules', modules);
-        module.change.setting('verbose', false, modules, modifyExisting);
-      }
-    },
-
-    console: function(enable) {
-      if(enable) {
-        if(instance.cache.console === undefined) {
-          module.error(error.console);
-          return;
-        }
-        module.debug('Restoring console function');
-        window.console = instance.cache.console;
-      }
-      else {
-        module.debug('Disabling console function');
-        instance.cache.console = window.console;
-        window.console = {
-          clear          : function(){},
-          error          : function(){},
-          group          : function(){},
-          groupCollapsed : function(){},
-          groupEnd       : function(){},
-          info           : function(){},
-          log            : function(){},
-          markTimeline   : function(){},
-          warn           : function(){}
-        };
-      }
-    },
-
-    destroy: function() {
-      module.verbose('Destroying previous site for', $module);
-      $module
-        .removeData(moduleNamespace)
-      ;
-    },
-
-    cache: {},
-
-    setting: function(name, value) {
-      if( $.isPlainObject(name) ) {
-        $.extend(true, settings, name);
-      }
-      else if(value !== undefined) {
-        settings[name] = value;
-      }
-      else {
-        return settings[name];
-      }
-    },
-    internal: function(name, value) {
-      if( $.isPlainObject(name) ) {
-        $.extend(true, module, name);
-      }
-      else if(value !== undefined) {
-        module[name] = value;
-      }
-      else {
-        return module[name];
-      }
-    },
-    debug: function() {
-      if(settings.debug) {
-        if(settings.performance) {
-          module.performance.log(arguments);
-        }
-        else {
-          module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
-          module.debug.apply(console, arguments);
-        }
-      }
-    },
-    verbose: function() {
-      if(settings.verbose && settings.debug) {
-        if(settings.performance) {
-          module.performance.log(arguments);
-        }
-        else {
-          module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
-          module.verbose.apply(console, arguments);
-        }
-      }
-    },
-    error: function() {
-      module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
-      module.error.apply(console, arguments);
-    },
-    performance: {
-      log: function(message) {
-        var
-          currentTime,
-          executionTime,
-          previousTime
-        ;
-        if(settings.performance) {
-          currentTime   = new Date().getTime();
-          previousTime  = time || currentTime;
-          executionTime = currentTime - previousTime;
-          time          = currentTime;
-          performance.push({
-            'Element'        : element,
-            'Name'           : message[0],
-            'Arguments'      : [].slice.call(message, 1) || '',
-            'Execution Time' : executionTime
-          });
-        }
-        clearTimeout(module.performance.timer);
-        module.performance.timer = setTimeout(module.performance.display, 500);
-      },
-      display: function() {
-        var
-          title = settings.name + ':',
-          totalTime = 0
-        ;
-        time = false;
-        clearTimeout(module.performance.timer);
-        $.each(performance, function(index, data) {
-          totalTime += data['Execution Time'];
-        });
-        title += ' ' + totalTime + 'ms';
-        if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
-          console.groupCollapsed(title);
-          if(console.table) {
-            console.table(performance);
-          }
-          else {
-            $.each(performance, function(index, data) {
-              console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
-            });
-          }
-          console.groupEnd();
-        }
-        performance = [];
-      }
-    },
-    invoke: function(query, passedArguments, context) {
-      var
-        object = instance,
-        maxDepth,
-        found,
-        response
-      ;
-      passedArguments = passedArguments || queryArguments;
-      context         = element         || context;
-      if(typeof query == 'string' && object !== undefined) {
-        query    = query.split(/[\. ]/);
-        maxDepth = query.length - 1;
-        $.each(query, function(depth, value) {
-          var camelCaseValue = (depth != maxDepth)
-            ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
-            : query
-          ;
-          if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
-            object = object[camelCaseValue];
-          }
-          else if( object[camelCaseValue] !== undefined ) {
-            found = object[camelCaseValue];
-            return false;
-          }
-          else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
-            object = object[value];
-          }
-          else if( object[value] !== undefined ) {
-            found = object[value];
-            return false;
-          }
-          else {
-            module.error(error.method, query);
-            return false;
-          }
-        });
-      }
-      if ( $.isFunction( found ) ) {
-        response = found.apply(context, passedArguments);
-      }
-      else if(found !== undefined) {
-        response = found;
-      }
-      if(Array.isArray(returnedValue)) {
-        returnedValue.push(response);
-      }
-      else if(returnedValue !== undefined) {
-        returnedValue = [returnedValue, response];
-      }
-      else if(response !== undefined) {
-        returnedValue = response;
-      }
-      return found;
-    }
-  };
-
-  if(methodInvoked) {
-    if(instance === undefined) {
-      module.initialize();
-    }
-    module.invoke(query);
-  }
-  else {
-    if(instance !== undefined) {
-      module.destroy();
-    }
-    module.initialize();
-  }
-  return (returnedValue !== undefined)
-    ? returnedValue
-    : this
-  ;
-};
-
-$.site.settings = {
-
-  name        : 'Site',
-  namespace   : 'site',
-
-  error : {
-    console : 'Console cannot be restored, most likely it was overwritten outside of module',
-    method : 'The method you called is not defined.'
-  },
-
-  debug       : false,
-  verbose     : false,
-  performance : true,
-
-  modules: [
-    'accordion',
-    'api',
-    'calendar',
-    'checkbox',
-    'dimmer',
-    'dropdown',
-    'embed',
-    'form',
-    'modal',
-    'nag',
-    'popup',
-    'slider',
-    'rating',
-    'shape',
-    'sidebar',
-    'state',
-    'sticky',
-    'tab',
-    'toast',
-    'transition',
-    'visibility',
-    'visit'
-  ],
-
-  siteNamespace   : 'site',
-  namespaceStub   : {
-    cache     : {},
-    config    : {},
-    sections  : {},
-    section   : {},
-    utilities : {}
-  }
-
-};
-
-// allows for selection of elements with data attributes
-$.extend($.expr[ ":" ], {
-  data: ($.expr.createPseudo)
-    ? $.expr.createPseudo(function(dataName) {
-        return function(elem) {
-          return !!$.data(elem, dataName);
-        };
-      })
-    : function(elem, i, match) {
-      // support: jQuery < 1.8
-      return !!$.data(elem, match[ 3 ]);
-    }
-});
-
-
 })( jQuery, window, document );
 
 /*!
diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json
index 6e2facf82..367bdf364 100644
--- a/web_src/fomantic/semantic.json
+++ b/web_src/fomantic/semantic.json
@@ -28,7 +28,6 @@
     "dimmer",
     "dropdown",
     "form",
-    "grid",
     "header",
     "input",
     "label",
@@ -37,7 +36,6 @@
     "modal",
     "search",
     "segment",
-    "site",
     "tab",
     "table"
   ]
diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js
index 698d17fa3..303447819 100644
--- a/web_src/js/bootstrap.js
+++ b/web_src/js/bootstrap.js
@@ -23,7 +23,7 @@ export function showGlobalErrorMessage(msg) {
   let msgDiv = pageContent.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`);
   if (!msgDiv) {
     const el = document.createElement('div');
-    el.innerHTML = `<div class="ui container negative message center aligned js-global-error" style="white-space: pre-line;"></div>`;
+    el.innerHTML = `<div class="ui container negative message center aligned js-global-error tw-mt-[15px] tw-whitespace-pre-line"></div>`;
     msgDiv = el.childNodes[0];
   }
   // merge duplicated messages into "the message (count)" format
diff --git a/web_src/js/components/ActionRunStatus.vue b/web_src/js/components/ActionRunStatus.vue
index 51a774543..7ada543fe 100644
--- a/web_src/js/components/ActionRunStatus.vue
+++ b/web_src/js/components/ActionRunStatus.vue
@@ -10,25 +10,25 @@ export default {
   props: {
     status: {
       type: String,
-      required: true
+      required: true,
     },
     size: {
       type: Number,
-      default: 16
+      default: 16,
     },
     className: {
       type: String,
-      default: ''
+      default: '',
     },
     localeStatus: {
       type: String,
-      default: ''
-    }
+      default: '',
+    },
   },
 };
 </script>
 <template>
-  <span class="gt-df gt-ac" :data-tooltip-content="localeStatus" v-if="status">
+  <span class="tw-flex tw-items-center" :data-tooltip-content="localeStatus" v-if="status">
     <SvgIcon name="octicon-check-circle-fill" class="text green" :size="size" :class-name="className" v-if="status === 'success'"/>
     <SvgIcon name="octicon-skip" class="text grey" :size="size" :class-name="className" v-else-if="status === 'skipped'"/>
     <SvgIcon name="octicon-clock" class="text yellow" :size="size" :class-name="className" v-else-if="status === 'waiting'"/>
diff --git a/web_src/js/components/ActivityHeatmap.vue b/web_src/js/components/ActivityHeatmap.vue
index cc03f1bb2..be0841e83 100644
--- a/web_src/js/components/ActivityHeatmap.vue
+++ b/web_src/js/components/ActivityHeatmap.vue
@@ -11,7 +11,7 @@ export default {
     locale: {
       type: Object,
       default: () => {},
-    }
+    },
   },
   data: () => ({
     colorRange: [
@@ -49,7 +49,7 @@ export default {
 
       const newSearch = params.toString();
       window.location.search = newSearch.length ? `?${newSearch}` : '';
-    }
+    },
   },
 };
 </script>
diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue
index 3a1b828cc..149cabd41 100644
--- a/web_src/js/components/ContextPopup.vue
+++ b/web_src/js/components/ContextPopup.vue
@@ -69,7 +69,7 @@ export default {
         }
         return {name: label.name, color: `#${label.color}`, textColor};
       });
-    }
+    },
   },
   mounted() {
     this.$refs.root.addEventListener('ce-load-context-popup', (e) => {
@@ -97,8 +97,8 @@ export default {
       } finally {
         this.loading = false;
       }
-    }
-  }
+    },
+  },
 };
 </script>
 <template>
diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue
index 825803d93..64de258f9 100644
--- a/web_src/js/components/DashboardRepoList.vue
+++ b/web_src/js/components/DashboardRepoList.vue
@@ -235,7 +235,7 @@ const sfc = {
         if (!this.reposTotalCount) {
           const totalCountSearchURL = `${this.subUrl}/repo/search?count_only=1&uid=${this.uid}&team_id=${this.teamId}&q=&page=1&mode=`;
           response = await GET(totalCountSearchURL);
-          this.reposTotalCount = response.headers.get('X-Total-Count');
+          this.reposTotalCount = response.headers.get('X-Total-Count') ?? '?';
         }
 
         response = await GET(searchedURL);
@@ -252,7 +252,7 @@ const sfc = {
           return {
             ...webSearchRepo.repository,
             latest_commit_status: webSearchRepo.latest_commit_status,
-            locale_latest_commit_status_state: webSearchRepo.locale_latest_commit_status
+            locale_latest_commit_status: webSearchRepo.locale_latest_commit_status,
           };
         });
         const count = response.headers.get('X-Total-Count');
@@ -324,7 +324,7 @@ const sfc = {
       if (this.activeIndex === -1 || this.activeIndex > this.repos.length - 1) {
         this.activeIndex = 0;
       }
-    }
+    },
   },
 };
 
@@ -344,8 +344,8 @@ export default sfc; // activate the IDE's Vue plugin
       <a :class="{item: true, active: tab === 'organizations'}" @click="changeTab('organizations')">{{ textMyOrgs }} <span class="ui grey label gt-ml-3">{{ organizationsTotalCount }}</span></a>
     </div>
     <div v-show="tab === 'repos'" class="ui tab active list dashboard-repos">
-      <h4 v-if="isOrganization" class="ui top attached gt-mt-4 gt-df gt-ac">
-        <div class="gt-f1 gt-df gt-ac">
+      <h4 v-if="isOrganization" class="ui top attached gt-mt-4 tw-flex tw-items-center">
+        <div class="tw-flex-1 tw-flex tw-items-center">
           {{ textMyRepos }}
           <span class="ui grey label gt-ml-3">{{ reposTotalCount }}</span>
         </div>
@@ -405,9 +405,9 @@ export default sfc; // activate the IDE's Vue plugin
           </div>
         </overflow-menu>
       </div>
-      <div v-if="repos.length" class="ui attached table segment gt-rounded-bottom">
+      <div v-if="repos.length" class="ui attached table segment tw-rounded-b">
         <ul class="repo-owner-name-list">
-          <li class="gt-df gt-ac gt-py-3" v-for="repo, index in repos" :class="{'active': index === activeIndex}" :key="repo.id">
+          <li class="tw-flex tw-items-center gt-py-3" v-for="repo, index in repos" :class="{'active': index === activeIndex}" :key="repo.id">
             <a class="repo-list-link muted" :href="repo.link">
               <svg-icon :name="repoIcon(repo)" :size="16" class-name="repo-list-icon"/>
               <div class="text truncate">{{ repo.full_name }}</div>
@@ -415,14 +415,15 @@ export default sfc; // activate the IDE's Vue plugin
                 <svg-icon name="octicon-archive" :size="16"/>
               </div>
             </a>
-            <a class="gt-df gt-ac" v-if="repo.latest_commit_status" :href="repo.latest_commit_status.TargetLink" :data-tooltip-content="repo.locale_latest_commit_status.State">
+            <a class="tw-flex tw-items-center" v-if="repo.latest_commit_status" :href="repo.latest_commit_status.TargetLink" :data-tooltip-content="repo.locale_latest_commit_status.State">
               <!-- the commit status icon logic is taken from templates/repo/commit_status.tmpl -->
               <svg-icon :name="statusIcon(repo.latest_commit_status.State)" :class-name="'gt-ml-3 commit-status icon text ' + statusColor(repo.latest_commit_status.State)" :size="16"/>
             </a>
           </li>
         </ul>
-        <div v-if="showMoreReposLink" class="center gt-py-3 gt-border-secondary-top">
-          <div class="ui borderless pagination menu narrow">
+        <div v-if="showMoreReposLink" class="tw-text-center">
+          <div class="divider gt-my-0"/>
+          <div class="ui borderless pagination menu narrow gt-my-3">
             <a
               class="item navigation gt-py-2" :class="{'disabled': page === 1}"
               @click="changePage(1)" :title="textFirstPage"
@@ -453,9 +454,9 @@ export default sfc; // activate the IDE's Vue plugin
       </div>
     </div>
     <div v-if="!isOrganization" v-show="tab === 'organizations'" class="ui tab active list dashboard-orgs">
-      <div v-if="organizations.length" class="ui attached table segment gt-rounded">
+      <div v-if="organizations.length" class="ui attached table segment tw-rounded-b">
         <ul class="repo-owner-name-list">
-          <li class="gt-df gt-ac gt-py-3" v-for="org in organizations" :key="org.name">
+          <li class="tw-flex tw-items-center gt-py-3" v-for="org in organizations" :key="org.name">
             <a class="repo-list-link muted" :href="subUrl + '/' + encodeURIComponent(org.name)">
               <svg-icon name="octicon-organization" :size="16" class-name="repo-list-icon"/>
               <div class="text truncate">{{ org.name }}</div>
@@ -465,7 +466,7 @@ export default sfc; // activate the IDE's Vue plugin
                 </span>
               </div>
             </a>
-            <div class="text light grey gt-df gt-ac gt-ml-3">
+            <div class="text light grey tw-flex tw-items-center gt-ml-3">
               {{ org.num_repos }}
               <svg-icon name="octicon-repo" :size="16" class-name="gt-ml-2 gt-mt-1"/>
             </div>
diff --git a/web_src/js/components/DiffCommitSelector.vue b/web_src/js/components/DiffCommitSelector.vue
index 780ba22f0..35245f219 100644
--- a/web_src/js/components/DiffCommitSelector.vue
+++ b/web_src/js/components/DiffCommitSelector.vue
@@ -14,7 +14,7 @@ export default {
       },
       commits: [],
       hoverActivated: false,
-      lastReviewCommitSha: null
+      lastReviewCommitSha: null,
     };
   },
   computed: {
@@ -29,7 +29,7 @@ export default {
     },
     issueLink() {
       return this.$el.parentNode.getAttribute('data-issuelink');
-    }
+    },
   },
   mounted() {
     document.body.addEventListener('click', this.onBodyClick);
@@ -185,7 +185,7 @@ export default {
         }
       }
     },
-  }
+  },
 };
 </script>
 <template>
@@ -204,7 +204,7 @@ export default {
     </button>
     <div class="menu left transition" id="diff-commit-selector-menu" :class="{visible: menuVisible}" v-show="menuVisible" v-cloak :aria-expanded="menuVisible ? 'true': 'false'">
       <div class="loading-indicator is-loading" v-if="isLoading"/>
-      <div v-if="!isLoading" class="vertical item gt-df gt-fc gt-gap-2" id="diff-commit-list-show-all" role="menuitem" @keydown.enter="showAllChanges()" @click="showAllChanges()">
+      <div v-if="!isLoading" class="vertical item" id="diff-commit-list-show-all" role="menuitem" @keydown.enter="showAllChanges()" @click="showAllChanges()">
         <div class="gt-ellipsis">
           {{ locale.show_all_commits }}
         </div>
@@ -215,7 +215,7 @@ export default {
       <!-- only show the show changes since last review if there is a review AND we are commits ahead of the last review -->
       <div
         v-if="lastReviewCommitSha != null" role="menuitem"
-        class="vertical item gt-df gt-fc gt-gap-2 gt-border-secondary-top"
+        class="vertical item"
         :class="{disabled: commitsSinceLastReview === 0}"
         @keydown.enter="changesSinceLastReviewClick()"
         @click="changesSinceLastReviewClick()"
@@ -227,10 +227,10 @@ export default {
           {{ commitsSinceLastReview }} commits
         </div>
       </div>
-      <span v-if="!isLoading" class="info gt-border-secondary-top text light-2">{{ locale.select_commit_hold_shift_for_range }}</span>
+      <span v-if="!isLoading" class="info text light-2">{{ locale.select_commit_hold_shift_for_range }}</span>
       <template v-for="commit in commits" :key="commit.id">
         <div
-          class="vertical item gt-df gt-gap-2 gt-border-secondary-top" role="menuitem"
+          class="vertical item" role="menuitem"
           :class="{selection: commit.selected, hovered: commit.hovered}"
           @keydown.enter.exact="commitClicked(commit.id)"
           @keydown.enter.shift.exact="commitClickedShift(commit)"
@@ -240,7 +240,7 @@ export default {
           @click.meta.exact="commitClicked(commit.id, true)"
           @click.shift.exact.stop.prevent="commitClickedShift(commit)"
         >
-          <div class="gt-f1 gt-df gt-fc gt-gap-2">
+          <div class="tw-flex-1 tw-flex tw-flex-col tw-gap-1">
             <div class="gt-ellipsis commit-list-summary">
               {{ commit.summary }}
             </div>
@@ -285,10 +285,14 @@ export default {
     width: 350px;
   }
 
-  #diff-commit-selector-menu .item {
+  #diff-commit-selector-menu .item,
+  #diff-commit-selector-menu .info {
+    display: flex !important;
     flex-direction: row;
     line-height: 1.4;
     padding: 7px 14px !important;
+    border-top: 1px solid var(--color-secondary) !important;
+    gap: 0.25em;
   }
 
   #diff-commit-selector-menu .item:focus {
diff --git a/web_src/js/components/DiffFileList.vue b/web_src/js/components/DiffFileList.vue
index 8bde61804..66fe49c50 100644
--- a/web_src/js/components/DiffFileList.vue
+++ b/web_src/js/components/DiffFileList.vue
@@ -31,14 +31,14 @@ export default {
     },
     loadMoreData() {
       loadMoreFiles(this.store.linkLoadMore);
-    }
+    },
   },
 };
 </script>
 <template>
   <ol class="diff-stats gt-m-0" ref="root" v-if="store.fileListIsVisible">
     <li v-for="file in store.files" :key="file.NameHash">
-      <div class="gt-font-semibold gt-df gt-ac pull-right">
+      <div class="tw-font-semibold tw-flex tw-items-center pull-right">
         <span v-if="file.IsBin" class="gt-ml-1 gt-mr-3">{{ store.binaryFileMessage }}</span>
         {{ file.IsBin ? '' : file.Addition + file.Deletion }}
         <span v-if="!file.IsBin" class="diff-stats-bar gt-mx-3" :data-tooltip-content="store.statisticsMessage.replace('%d', (file.Addition + file.Deletion)).replace('%d', file.Addition).replace('%d', file.Deletion)">
@@ -50,7 +50,7 @@ export default {
       <a class="file gt-mono" :href="'#diff-' + file.NameHash">{{ file.Name }}</a>
     </li>
     <li v-if="store.isIncomplete" class="gt-pt-2">
-      <span class="file gt-df gt-ac gt-sb">{{ store.tooManyFilesMessage }}
+      <span class="file tw-flex tw-items-center tw-justify-between">{{ store.tooManyFilesMessage }}
         <a :class="['ui', 'basic', 'tiny', 'button', store.isLoadingNewData ? 'disabled' : '']" @click.stop="loadMoreData">{{ store.showMoreMessage }}</a>
       </span>
     </li>
diff --git a/web_src/js/components/DiffFileTree.vue b/web_src/js/components/DiffFileTree.vue
index 3686629df..83d57b00d 100644
--- a/web_src/js/components/DiffFileTree.vue
+++ b/web_src/js/components/DiffFileTree.vue
@@ -30,7 +30,7 @@ export default {
           let newParent = {
             name: split,
             children: [],
-            isFile
+            isFile,
           };
 
           if (isFile === true) {
@@ -40,7 +40,7 @@ export default {
           if (parent) {
             // check if the folder already exists
             const existingFolder = parent.children.find(
-              (x) => x.name === split
+              (x) => x.name === split,
             );
             if (existingFolder) {
               newParent = existingFolder;
@@ -74,7 +74,7 @@ export default {
       // reduce the depth of our tree.
       mergeChildIfOnlyOneDir(result);
       return result;
-    }
+    },
   },
   mounted() {
     // Default to true if unset
diff --git a/web_src/js/components/DiffFileTreeItem.vue b/web_src/js/components/DiffFileTreeItem.vue
index 9d7ab4afc..0f6e54363 100644
--- a/web_src/js/components/DiffFileTreeItem.vue
+++ b/web_src/js/components/DiffFileTreeItem.vue
@@ -7,7 +7,7 @@ export default {
   props: {
     item: {
       type: Object,
-      required: true
+      required: true,
     },
   },
   data: () => ({
@@ -37,7 +37,7 @@ export default {
   >
     <!-- file -->
     <SvgIcon name="octicon-file"/>
-    <span class="gt-ellipsis gt-f1">{{ item.name }}</span>
+    <span class="gt-ellipsis tw-flex-1">{{ item.name }}</span>
     <SvgIcon :name="getIconForDiffType(item.file.Type).name" :class="getIconForDiffType(item.file.Type).classes"/>
   </a>
   <div v-else class="item-directory" :title="item.name" @click.stop="collapsed = !collapsed">
diff --git a/web_src/js/components/PullRequestMergeForm.vue b/web_src/js/components/PullRequestMergeForm.vue
index b0b10b625..35acbdf74 100644
--- a/web_src/js/components/PullRequestMergeForm.vue
+++ b/web_src/js/components/PullRequestMergeForm.vue
@@ -43,7 +43,7 @@ export default {
       for (const elem of document.querySelectorAll('[data-pull-merge-style]')) {
         toggleElem(elem, elem.getAttribute('data-pull-merge-style') === val);
       }
-    }
+    },
   },
   created() {
     this.mergeStyleAllowedCount = this.mergeForm.mergeStyles.reduce((v, msd) => v + (msd.allowed ? 1 : 0), 0);
@@ -94,6 +94,7 @@ export default {
     <!-- eslint-disable-next-line vue/no-v-html -->
     <div v-if="mergeForm.hasPendingPullRequestMerge" v-html="mergeForm.hasPendingPullRequestMergeTip" class="ui info message"/>
 
+    <!-- another similar form is in pull.tmpl (manual merge)-->
     <form class="ui form form-fetch-action" v-if="showActionForm" :action="mergeForm.baseLink+'/merge'" method="post">
       <input type="hidden" name="_csrf" :value="csrfToken">
       <input type="hidden" name="head_commit_id" v-model="mergeForm.pullHeadCommitID">
@@ -135,7 +136,7 @@ export default {
       </div>
     </form>
 
-    <div v-if="!showActionForm" class="gt-df">
+    <div v-if="!showActionForm" class="tw-flex">
       <!-- the merge button -->
       <div class="ui buttons merge-button" :class="[mergeForm.emptyCommit ? 'grey' : mergeForm.allOverridableChecksOk ? 'primary' : 'red']" @click="toggleActionForm(true)">
         <button class="ui button">
diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue
index 4a2106922..02e1dcd4d 100644
--- a/web_src/js/components/RepoActionView.vue
+++ b/web_src/js/components/RepoActionView.vue
@@ -69,7 +69,7 @@ const sfc = {
             name: '',
             link: '',
           },
-        }
+        },
       },
       currentJob: {
         title: '',
@@ -271,6 +271,10 @@ const sfc = {
       return ['success', 'skipped', 'failure', 'cancelled'].includes(status);
     },
 
+    isExpandable(status) {
+      return ['success', 'running', 'failure', 'cancelled'].includes(status);
+    },
+
     closeDropdown() {
       if (this.menuVisible) this.menuVisible = false;
     },
@@ -314,7 +318,7 @@ const sfc = {
       const logLine = this.$refs.steps.querySelector(selectedLogStep);
       if (!logLine) return;
       logLine.querySelector('.line-num').click();
-    }
+    },
   },
 };
 
@@ -357,7 +361,7 @@ export function initRepositoryActionView() {
         skipped: el.getAttribute('data-locale-status-skipped'),
         blocked: el.getAttribute('data-locale-status-blocked'),
       },
-    }
+    },
   });
   view.mount(el);
 }
@@ -468,12 +472,12 @@ export function initRepositoryActionView() {
         </div>
         <div class="job-step-container" ref="steps" v-if="currentJob.steps.length">
           <div class="job-step-section" v-for="(jobStep, i) in currentJob.steps" :key="i">
-            <div class="job-step-summary" @click.stop="toggleStepLogs(i)" :class="currentJobStepsStates[i].expanded ? 'selected' : ''">
+            <div class="job-step-summary" @click.stop="jobStep.status !== 'skipped' && toggleStepLogs(i)" :class="[currentJobStepsStates[i].expanded ? 'selected' : '', isExpandable(jobStep.status) && 'step-expandable']">
               <!-- If the job is done and the job step log is loaded for the first time, show the loading icon
                 currentJobStepsStates[i].cursor === null means the log is loaded for the first time
               -->
               <SvgIcon v-if="isDone(run.status) && currentJobStepsStates[i].expanded && currentJobStepsStates[i].cursor === null" name="octicon-sync" class="gt-mr-3 job-status-rotate"/>
-              <SvgIcon v-else :name="currentJobStepsStates[i].expanded ? 'octicon-chevron-down': 'octicon-chevron-right'" class="gt-mr-3"/>
+              <SvgIcon v-else :name="currentJobStepsStates[i].expanded ? 'octicon-chevron-down': 'octicon-chevron-right'" :class="['gt-mr-3', !isExpandable(jobStep.status) && 'tw-invisible']"/>
               <ActionRunStatus :status="jobStep.status" class="gt-mr-3"/>
 
               <span class="step-summary-msg gt-ellipsis">{{ jobStep.summary }}</span>
@@ -724,13 +728,21 @@ export function initRepositoryActionView() {
 }
 
 .job-step-container .job-step-summary {
-  cursor: pointer;
   padding: 5px 10px;
   display: flex;
   align-items: center;
   border-radius: var(--border-radius);
 }
 
+.job-step-container .job-step-summary.step-expandable {
+  cursor: pointer;
+}
+
+.job-step-container .job-step-summary.step-expandable:hover {
+  color: var(--color-console-fg);
+  background-color: var(--color-console-hover-bg);
+}
+
 .job-step-container .job-step-summary .step-summary-msg {
   flex: 1;
 }
@@ -739,12 +751,6 @@ export function initRepositoryActionView() {
   margin-left: 16px;
 }
 
-.job-step-container .job-step-summary:hover {
-  color: var(--color-console-fg);
-  background-color: var(--color-console-hover-bg);
-
-}
-
 .job-step-container .job-step-summary.selected {
   color: var(--color-console-fg);
   background-color: var(--color-console-active-bg);
diff --git a/web_src/js/components/RepoActivityTopAuthors.vue b/web_src/js/components/RepoActivityTopAuthors.vue
index fe41218d8..a41fb61d7 100644
--- a/web_src/js/components/RepoActivityTopAuthors.vue
+++ b/web_src/js/components/RepoActivityTopAuthors.vue
@@ -47,7 +47,7 @@ const sfc = {
     this.colors.barColor = refStyle.backgroundColor;
     this.colors.textColor = refStyle.color;
     this.colors.textAltColor = refAltStyle.color;
-  }
+  },
 };
 
 export function initRepoActivityTopAuthorsChart() {
diff --git a/web_src/js/components/RepoBranchTagSelector.vue b/web_src/js/components/RepoBranchTagSelector.vue
index 83289c885..34e885960 100644
--- a/web_src/js/components/RepoBranchTagSelector.vue
+++ b/web_src/js/components/RepoBranchTagSelector.vue
@@ -36,7 +36,7 @@ const sfc = {
     },
     shouldCreateTag() {
       return this.mode === 'tags';
-    }
+    },
   },
 
   watch: {
@@ -45,7 +45,7 @@ const sfc = {
         this.focusSearchField();
         this.fetchBranchesOrTags();
       }
-    }
+    },
   },
 
   beforeMount() {
@@ -83,7 +83,7 @@ const sfc = {
         this.isViewBranch = false;
         this.$refs.dropdownRefName.textContent = item.name;
         if (this.setAction) {
-          $(`#${this.branchForm}`).attr('action', url);
+          document.getElementById(this.branchForm)?.setAttribute('action', url);
         } else {
           $(`#${this.branchForm} input[name="refURL"]`).val(url);
         }
@@ -209,7 +209,7 @@ const sfc = {
         this.isLoading = false;
       }
     },
-  }
+  },
 };
 
 export function initRepoBranchTagSelector(selector) {
@@ -245,8 +245,8 @@ export default sfc; // activate IDE's Vue plugin
 </script>
 <template>
   <div class="ui dropdown custom">
-    <button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df gt-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible">
-      <span class="text gt-df gt-ac gt-mr-2">
+    <button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex gt-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible">
+      <span class="text tw-flex tw-items-center gt-mr-2">
         <template v-if="release">{{ textReleaseCompare }}</template>
         <template v-else>
           <svg-icon v-if="isViewTag" name="octicon-tag"/>
diff --git a/web_src/js/components/RepoCodeFrequency.vue b/web_src/js/components/RepoCodeFrequency.vue
index ad607a041..f51dac0a6 100644
--- a/web_src/js/components/RepoCodeFrequency.vue
+++ b/web_src/js/components/RepoCodeFrequency.vue
@@ -39,7 +39,7 @@ export default {
   props: {
     locale: {
       type: Object,
-      required: true
+      required: true,
     },
   },
   data: () => ({
@@ -128,12 +128,12 @@ export default {
             },
             ticks: {
               maxRotation: 0,
-              maxTicksLimit: 12
+              maxTicksLimit: 12,
             },
           },
           y: {
             ticks: {
-              maxTicksLimit: 6
+              maxTicksLimit: 6,
             },
           },
         },
@@ -144,11 +144,11 @@ export default {
 </script>
 <template>
   <div>
-    <div class="ui header gt-df gt-ac gt-sb">
+    <div class="ui header tw-flex tw-items-center tw-justify-between">
       {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: `Code frequency over the history of ${repoLink.slice(1)}` }}
     </div>
-    <div class="gt-df ui segment main-graph">
-      <div v-if="isLoading || errorText !== ''" class="gt-tc gt-m-auto">
+    <div class="tw-flex ui segment main-graph">
+      <div v-if="isLoading || errorText !== ''" class="gt-tc tw-m-auto">
         <div v-if="isLoading">
           <SvgIcon name="octicon-sync" class="gt-mr-3 job-status-rotate"/>
           {{ locale.loadingInfo }}
diff --git a/web_src/js/components/RepoContributors.vue b/web_src/js/components/RepoContributors.vue
index 22c247ae3..02db9e3e3 100644
--- a/web_src/js/components/RepoContributors.vue
+++ b/web_src/js/components/RepoContributors.vue
@@ -34,7 +34,7 @@ const customEventListener = {
       chart.resetZoom();
       opts.instance.updateOtherCharts(args.event, true);
     }
-  }
+  },
 };
 
 Chart.defaults.color = chartJsColors.text;
@@ -82,7 +82,7 @@ export default {
         this.xAxisMax = this.xAxisEnd;
         this.type = val;
         this.sortContributors();
-      }
+      },
     });
   },
   methods: {
@@ -175,7 +175,7 @@ export default {
       // Normally, chartjs handles this automatically, but it will resize the graph when you
       // zoom, pan etc. I think resizing the graph makes it harder to compare things visually.
       const maxValue = Math.max(
-        ...this.totalStats.weeks.map((o) => o[this.type])
+        ...this.totalStats.weeks.map((o) => o[this.type]),
       );
       const [coefficient, exp] = maxValue.toExponential().split('e').map(Number);
       if (coefficient % 1 === 0) return maxValue;
@@ -187,7 +187,7 @@ export default {
       // for contributors' graph. If I let chartjs do this for me, it will choose different
       // maxY value for each contributors' graph which again makes it harder to compare.
       const maxValue = Math.max(
-        ...this.sortedContributors.map((c) => c.max_contribution_type)
+        ...this.sortedContributors.map((c) => c.max_contribution_type),
       );
       const [coefficient, exp] = maxValue.toExponential().split('e').map(Number);
       if (coefficient % 1 === 0) return maxValue;
@@ -303,7 +303,7 @@ export default {
 </script>
 <template>
   <div>
-    <div class="ui header gt-df gt-ac gt-sb">
+    <div class="ui header tw-flex tw-items-center tw-justify-between">
       <div>
         <relative-time
           v-if="xAxisMin > 0"
@@ -352,8 +352,8 @@ export default {
         </div>
       </div>
     </div>
-    <div class="gt-df ui segment main-graph">
-      <div v-if="isLoading || errorText !== ''" class="gt-tc gt-m-auto">
+    <div class="tw-flex ui segment main-graph">
+      <div v-if="isLoading || errorText !== ''" class="gt-tc tw-m-auto">
         <div v-if="isLoading">
           <SvgIcon name="octicon-sync" class="gt-mr-3 job-status-rotate"/>
           {{ locale.loadingInfo }}
@@ -374,17 +374,17 @@ export default {
         :key="index"
         v-memo="[sortedContributors, type]"
       >
-        <div class="ui top attached header gt-df gt-f1">
+        <div class="ui top attached header tw-flex tw-flex-1">
           <b class="ui right">#{{ index + 1 }}</b>
           <a :href="contributor.home_link">
-            <img class="ui avatar gt-vm" height="40" width="40" :src="contributor.avatar_link">
+            <img class="ui avatar tw-align-middle" height="40" width="40" :src="contributor.avatar_link">
           </a>
           <div class="gt-ml-3">
             <a v-if="contributor.home_link !== ''" :href="contributor.home_link"><h4>{{ contributor.name }}</h4></a>
             <h4 v-else class="contributor-name">
               {{ contributor.name }}
             </h4>
-            <p class="gt-font-12 gt-df gt-gap-2">
+            <p class="tw-text-12 tw-flex tw-gap-1">
               <strong v-if="contributor.total_commits">{{ contributor.total_commits.toLocaleString() }} {{ locale.contributionType.commits }}</strong>
               <strong v-if="contributor.total_additions" class="text green">{{ contributor.total_additions.toLocaleString() }}++ </strong>
               <strong v-if="contributor.total_deletions" class="text red">
diff --git a/web_src/js/components/RepoRecentCommits.vue b/web_src/js/components/RepoRecentCommits.vue
index 77697cd41..601252419 100644
--- a/web_src/js/components/RepoRecentCommits.vue
+++ b/web_src/js/components/RepoRecentCommits.vue
@@ -35,7 +35,7 @@ export default {
   props: {
     locale: {
       type: Object,
-      required: true
+      required: true,
     },
   },
   data: () => ({
@@ -105,12 +105,12 @@ export default {
             },
             ticks: {
               maxRotation: 0,
-              maxTicksLimit: 52
+              maxTicksLimit: 52,
             },
           },
           y: {
             ticks: {
-              maxTicksLimit: 6
+              maxTicksLimit: 6,
             },
           },
         },
@@ -121,11 +121,11 @@ export default {
 </script>
 <template>
   <div>
-    <div class="ui header gt-df gt-ac gt-sb">
+    <div class="ui header tw-flex tw-items-center tw-justify-between">
       {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: "Number of commits in the past year" }}
     </div>
-    <div class="gt-df ui segment main-graph">
-      <div v-if="isLoading || errorText !== ''" class="gt-tc gt-m-auto">
+    <div class="tw-flex ui segment main-graph">
+      <div v-if="isLoading || errorText !== ''" class="gt-tc tw-m-auto">
         <div v-if="isLoading">
           <SvgIcon name="octicon-sync" class="gt-mr-3 job-status-rotate"/>
           {{ locale.loadingInfo }}
diff --git a/web_src/js/components/ScopedAccessTokenSelector.vue b/web_src/js/components/ScopedAccessTokenSelector.vue
index f6af7e447..ae4e8299f 100644
--- a/web_src/js/components/ScopedAccessTokenSelector.vue
+++ b/web_src/js/components/ScopedAccessTokenSelector.vue
@@ -39,7 +39,7 @@ const sfc = {
         'repository',
         'user');
       return categories;
-    }
+    },
   },
 
   mounted() {
@@ -68,7 +68,7 @@ const sfc = {
       }
       // no scopes selected, show validation error
       showElem(warningEl);
-    }
+    },
   },
 };
 
diff --git a/web_src/js/features/admin/common.js b/web_src/js/features/admin/common.js
index 31d840c3e..0c65f04ab 100644
--- a/web_src/js/features/admin/common.js
+++ b/web_src/js/features/admin/common.js
@@ -208,7 +208,7 @@ export function initAdminCommon() {
     $('#delete-selection').on('click', async function (e) {
       e.preventDefault();
       const $this = $(this);
-      $this.addClass('loading disabled');
+      $this.addClass('is-loading disabled');
       const data = new FormData();
       $checkboxes.each(function () {
         if ($(this).checkbox('is checked')) {
diff --git a/web_src/js/features/captcha.js b/web_src/js/features/captcha.js
index 3da5dbda4..c803a5006 100644
--- a/web_src/js/features/captcha.js
+++ b/web_src/js/features/captcha.js
@@ -9,7 +9,7 @@ export async function initCaptcha() {
 
   const params = {
     sitekey: siteKey,
-    theme: isDark ? 'dark' : 'light'
+    theme: isDark ? 'dark' : 'light',
   };
 
   switch (captchaEl.getAttribute('data-captcha-type')) {
@@ -42,7 +42,7 @@ export async function initCaptcha() {
         siteKey: {
           instanceUrl: new URL(instanceURL),
           key: siteKey,
-        }
+        },
       });
       break;
     }
diff --git a/web_src/js/features/citation.js b/web_src/js/features/citation.js
index 49992b225..918a46713 100644
--- a/web_src/js/features/citation.js
+++ b/web_src/js/features/citation.js
@@ -1,8 +1,9 @@
 import $ from 'jquery';
+import {getCurrentLocale} from '../utils.js';
 
 const {pageData} = window.config;
 
-async function initInputCitationValue($citationCopyApa, $citationCopyBibtex) {
+async function initInputCitationValue(citationCopyApa, citationCopyBibtex) {
   const [{Cite, plugins}] = await Promise.all([
     import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'),
     import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'),
@@ -14,11 +15,11 @@ async function initInputCitationValue($citationCopyApa, $citationCopyBibtex) {
   config.constants.fieldTypes.doi = ['field', 'literal'];
   config.constants.fieldTypes.version = ['field', 'literal'];
   const citationFormatter = new Cite(citationFileContent);
-  const lang = document.documentElement.lang || 'en-US';
+  const lang = getCurrentLocale() || 'en-US';
   const apaOutput = citationFormatter.format('bibliography', {template: 'apa', lang});
   const bibtexOutput = citationFormatter.format('bibtex', {lang});
-  $citationCopyBibtex.attr('data-text', bibtexOutput);
-  $citationCopyApa.attr('data-text', apaOutput);
+  citationCopyBibtex.setAttribute('data-text', bibtexOutput);
+  citationCopyApa.setAttribute('data-text', apaOutput);
 }
 
 export async function initCitationFileCopyContent() {
@@ -26,44 +27,45 @@ export async function initCitationFileCopyContent() {
 
   if (!pageData.citationFileContent) return;
 
-  const $citationCopyApa = $('#citation-copy-apa');
-  const $citationCopyBibtex = $('#citation-copy-bibtex');
-  const $inputContent = $('#citation-copy-content');
+  const citationCopyApa = document.getElementById('citation-copy-apa');
+  const citationCopyBibtex = document.getElementById('citation-copy-bibtex');
+  const inputContent = document.getElementById('citation-copy-content');
+
+  if ((!citationCopyApa && !citationCopyBibtex) || !inputContent) return;
 
-  if ((!$citationCopyApa.length && !$citationCopyBibtex.length) || !$inputContent.length) return;
   const updateUi = () => {
     const isBibtex = (localStorage.getItem('citation-copy-format') || defaultCitationFormat) === 'bibtex';
-    const copyContent = (isBibtex ? $citationCopyBibtex : $citationCopyApa).attr('data-text');
-
-    $inputContent.val(copyContent);
-    $citationCopyBibtex.toggleClass('primary', isBibtex);
-    $citationCopyApa.toggleClass('primary', !isBibtex);
+    const copyContent = (isBibtex ? citationCopyBibtex : citationCopyApa).getAttribute('data-text');
+    inputContent.value = copyContent;
+    citationCopyBibtex.classList.toggle('primary', isBibtex);
+    citationCopyApa.classList.toggle('primary', !isBibtex);
   };
 
-  $('#cite-repo-button').on('click', async (e) => {
+  document.getElementById('cite-repo-button')?.addEventListener('click', async (e) => {
     const dropdownBtn = e.target.closest('.ui.dropdown.button');
     dropdownBtn.classList.add('is-loading');
 
     try {
       try {
-        await initInputCitationValue($citationCopyApa, $citationCopyBibtex);
+        await initInputCitationValue(citationCopyApa, citationCopyBibtex);
       } catch (e) {
         console.error(`initCitationFileCopyContent error: ${e}`, e);
         return;
       }
       updateUi();
 
-      $citationCopyApa.on('click', () => {
+      citationCopyApa.addEventListener('click', () => {
         localStorage.setItem('citation-copy-format', 'apa');
         updateUi();
       });
-      $citationCopyBibtex.on('click', () => {
+
+      citationCopyBibtex.addEventListener('click', () => {
         localStorage.setItem('citation-copy-format', 'bibtex');
         updateUi();
       });
 
-      $inputContent.on('click', () => {
-        $inputContent.trigger('select');
+      inputContent.addEventListener('click', () => {
+        inputContent.select();
       });
     } finally {
       dropdownBtn.classList.remove('is-loading');
diff --git a/web_src/js/features/code-frequency.js b/web_src/js/features/code-frequency.js
index 103d82f6e..47e1539dd 100644
--- a/web_src/js/features/code-frequency.js
+++ b/web_src/js/features/code-frequency.js
@@ -11,7 +11,7 @@ export async function initRepoCodeFrequency() {
         loadingTitle: el.getAttribute('data-locale-loading-title'),
         loadingTitleFailed: el.getAttribute('data-locale-loading-title-failed'),
         loadingInfo: el.getAttribute('data-locale-loading-info'),
-      }
+      },
     });
     View.mount(el);
   } catch (err) {
diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js
index fceb2f762..4fb8bb9e6 100644
--- a/web_src/js/features/codeeditor.js
+++ b/web_src/js/features/codeeditor.js
@@ -80,7 +80,7 @@ export async function createMonaco(textarea, filename, editorOpts) {
     rules: [
       {
         background: getColor('--color-code-bg'),
-      }
+      },
     ],
     colors: {
       'editor.background': getColor('--color-code-bg'),
@@ -98,7 +98,7 @@ export async function createMonaco(textarea, filename, editorOpts) {
       'input.foreground': getColor('--color-input-text'),
       'scrollbar.shadow': getColor('--color-shadow'),
       'progressBar.background': getColor('--color-primary'),
-    }
+    },
   });
 
   // Quick fix: https://github.com/microsoft/monaco-editor/issues/2962
diff --git a/web_src/js/features/colorpicker.js b/web_src/js/features/colorpicker.js
index a5fdb3f5a..df0353376 100644
--- a/web_src/js/features/colorpicker.js
+++ b/web_src/js/features/colorpicker.js
@@ -1,10 +1,12 @@
-export async function createColorPicker($els) {
-  if (!$els || !$els.length) return;
+import $ from 'jquery';
+
+export async function createColorPicker(els) {
+  if (!els.length) return;
 
   await Promise.all([
     import(/* webpackChunkName: "minicolors" */'@claviska/jquery-minicolors'),
     import(/* webpackChunkName: "minicolors" */'@claviska/jquery-minicolors/jquery.minicolors.css'),
   ]);
 
-  $els.minicolors();
+  return $(els).minicolors();
 }
diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js
index d99f606c8..e27935a86 100644
--- a/web_src/js/features/common-global.js
+++ b/web_src/js/features/common-global.js
@@ -301,8 +301,8 @@ export function initGlobalLinkActions() {
     const $this = $(this);
     const dataArray = $this.data();
     let filter = '';
-    if ($this.attr('data-modal-id')) {
-      filter += `#${$this.attr('data-modal-id')}`;
+    if (this.getAttribute('data-modal-id')) {
+      filter += `#${this.getAttribute('data-modal-id')}`;
     }
 
     const $dialog = $(`.delete.modal${filter}`);
@@ -335,7 +335,7 @@ export function initGlobalLinkActions() {
           const data = await response.json();
           window.location.href = data.redirect;
         }
-      }
+      },
     }).modal('show');
   }
 
@@ -352,8 +352,7 @@ function initGlobalShowModal() {
   // If there is a ".{attr}" part like "data-modal-form.action", then the form's "action" attribute will be set.
   $('.show-modal').on('click', function (e) {
     e.preventDefault();
-    const $el = $(this);
-    const modalSelector = $el.attr('data-modal');
+    const modalSelector = this.getAttribute('data-modal');
     const $modal = $(modalSelector);
     if (!$modal.length) {
       throw new Error('no modal for this action');
@@ -406,7 +405,7 @@ export function initGlobalButtons() {
     // a '.show-panel' element can show a panel, by `data-panel="selector"`
     // if it has "toggle" class, it toggles the panel
     e.preventDefault();
-    const sel = $(this).attr('data-panel');
+    const sel = this.getAttribute('data-panel');
     if (this.classList.contains('toggle')) {
       toggleElem(sel);
     } else {
@@ -417,12 +416,12 @@ export function initGlobalButtons() {
   $('.hide-panel').on('click', function (e) {
     // a `.hide-panel` element can hide a panel, by `data-panel="selector"` or `data-panel-closest="selector"`
     e.preventDefault();
-    let sel = $(this).attr('data-panel');
+    let sel = this.getAttribute('data-panel');
     if (sel) {
       hideElem($(sel));
       return;
     }
-    sel = $(this).attr('data-panel-closest');
+    sel = this.getAttribute('data-panel-closest');
     if (sel) {
       hideElem($(this).closest(sel));
       return;
diff --git a/web_src/js/features/common-issue-list.js b/web_src/js/features/common-issue-list.js
index 317c11219..0c0f6c563 100644
--- a/web_src/js/features/common-issue-list.js
+++ b/web_src/js/features/common-issue-list.js
@@ -1,4 +1,3 @@
-import $ from 'jquery';
 import {isElemHidden, onInputDebounce, submitEventSubmitter, toggleElem} from '../utils/dom.js';
 import {GET} from '../modules/fetch.js';
 
@@ -30,42 +29,40 @@ export function parseIssueListQuickGotoLink(repoLink, searchText) {
 }
 
 export function initCommonIssueListQuickGoto() {
-  const $goto = $('#issue-list-quick-goto');
-  if (!$goto.length) return;
+  const goto = document.getElementById('issue-list-quick-goto');
+  if (!goto) return;
 
-  const $form = $goto.closest('form');
-  const $input = $form.find('input[name=q]');
-  const repoLink = $goto.attr('data-repo-link');
+  const form = goto.closest('form');
+  const input = form.querySelector('input[name=q]');
+  const repoLink = goto.getAttribute('data-repo-link');
 
-  $form.on('submit', (e) => {
+  form.addEventListener('submit', (e) => {
     // if there is no goto button, or the form is submitted by non-quick-goto elements, submit the form directly
-    let doQuickGoto = !isElemHidden($goto);
-    const submitter = submitEventSubmitter(e.originalEvent);
-    if (submitter !== $form[0] && submitter !== $input[0] && submitter !== $goto[0]) doQuickGoto = false;
+    let doQuickGoto = !isElemHidden(goto);
+    const submitter = submitEventSubmitter(e);
+    if (submitter !== form && submitter !== input && submitter !== goto) doQuickGoto = false;
     if (!doQuickGoto) return;
 
     // if there is a goto button, use its link
     e.preventDefault();
-    window.location.href = $goto.attr('data-issue-goto-link');
+    window.location.href = goto.getAttribute('data-issue-goto-link');
   });
 
   const onInput = async () => {
-    const searchText = $input.val();
-
+    const searchText = input.value;
     // try to check whether the parsed goto link is valid
     let targetUrl = parseIssueListQuickGotoLink(repoLink, searchText);
     if (targetUrl) {
       const res = await GET(`${targetUrl}/info`);
       if (res.status !== 200) targetUrl = '';
     }
-
     // if the input value has changed, then ignore the result
-    if ($input.val() !== searchText) return;
+    if (input.value !== searchText) return;
 
-    toggleElem($goto, Boolean(targetUrl));
-    $goto.attr('data-issue-goto-link', targetUrl);
+    toggleElem(goto, Boolean(targetUrl));
+    goto.setAttribute('data-issue-goto-link', targetUrl);
   };
 
-  $input.on('input', onInputDebounce(onInput));
+  input.addEventListener('input', onInputDebounce(onInput));
   onInput();
 }
diff --git a/web_src/js/features/comp/ColorPicker.js b/web_src/js/features/comp/ColorPicker.js
index 5665b7a24..d7e703880 100644
--- a/web_src/js/features/comp/ColorPicker.js
+++ b/web_src/js/features/comp/ColorPicker.js
@@ -2,11 +2,15 @@ import $ from 'jquery';
 import {createColorPicker} from '../colorpicker.js';
 
 export function initCompColorPicker() {
-  createColorPicker($('.color-picker'));
+  (async () => {
+    await createColorPicker(document.querySelectorAll('.color-picker'));
 
-  $('.precolors .color').on('click', function () {
-    const color_hex = $(this).data('color-hex');
-    $('.color-picker').val(color_hex);
-    $('.minicolors-swatch-color').css('background-color', color_hex);
-  });
+    for (const el of document.querySelectorAll('.precolors .color')) {
+      el.addEventListener('click', (e) => {
+        const color = e.target.getAttribute('data-color-hex');
+        const parent = e.target.closest('.color.picker');
+        $(parent.querySelector('.color-picker')).minicolors('value', color);
+      });
+    }
+  })();
 }
diff --git a/web_src/js/features/comp/EasyMDEToolbarActions.js b/web_src/js/features/comp/EasyMDEToolbarActions.js
index 8286d5d87..c97d68370 100644
--- a/web_src/js/features/comp/EasyMDEToolbarActions.js
+++ b/web_src/js/features/comp/EasyMDEToolbarActions.js
@@ -139,7 +139,7 @@ export function easyMDEToolbarActions(EasyMDE, editor) {
       },
       icon: svg('octicon-chevron-right'),
       title: 'Add Inline Code',
-    }
+    },
   };
 
   for (const [key, value] of Object.entries(actions)) {
diff --git a/web_src/js/features/comp/LabelEdit.js b/web_src/js/features/comp/LabelEdit.js
index 26800ae05..44fc9d9b6 100644
--- a/web_src/js/features/comp/LabelEdit.js
+++ b/web_src/js/features/comp/LabelEdit.js
@@ -43,7 +43,6 @@ export function initCompLabelEdit(selector) {
 
   // Edit label
   $('.edit-label-button').on('click', function () {
-    $('.edit-label .color-picker').minicolors('value', $(this).data('color'));
     $('#label-modal-id').val($(this).data('id'));
 
     const $nameInput = $('.edit-label .label-name-input');
@@ -60,9 +59,8 @@ export function initCompLabelEdit(selector) {
       (!this.hasAttribute('data-exclusive') || !isExclusiveScopeName($nameInput.val())));
     updateExclusiveLabelEdit('.edit-label');
 
-    $('.edit-label .label-desc-input').val($(this).data('description'));
-    $('.edit-label .color-picker').val($(this).data('color'));
-    $('.edit-label .minicolors-swatch-color').css('background-color', $(this).data('color'));
+    $('.edit-label .label-desc-input').val(this.getAttribute('data-description'));
+    $('.edit-label .color-picker').minicolors('value', this.getAttribute('data-color'));
 
     $('.edit-label.modal').modal({
       onApprove() {
diff --git a/web_src/js/features/comp/SearchUserBox.js b/web_src/js/features/comp/SearchUserBox.js
index 992d4ef02..83d7044f1 100644
--- a/web_src/js/features/comp/SearchUserBox.js
+++ b/web_src/js/features/comp/SearchUserBox.js
@@ -5,9 +5,12 @@ const {appSubUrl} = window.config;
 const looksLikeEmailAddressCheck = /^\S+@\S+$/;
 
 export function initCompSearchUserBox() {
-  const $searchUserBox = $('#search-user-box');
-  const allowEmailInput = $searchUserBox.attr('data-allow-email') === 'true';
-  const allowEmailDescription = $searchUserBox.attr('data-allow-email-description');
+  const searchUserBox = document.getElementById('search-user-box');
+  if (!searchUserBox) return;
+
+  const $searchUserBox = $(searchUserBox);
+  const allowEmailInput = searchUserBox.getAttribute('data-allow-email') === 'true';
+  const allowEmailDescription = searchUserBox.getAttribute('data-allow-email-description') ?? undefined;
   $searchUserBox.search({
     minCharacters: 2,
     apiSettings: {
@@ -19,7 +22,7 @@ export function initCompSearchUserBox() {
         $.each(response.data, (_i, item) => {
           const resultItem = {
             title: item.login,
-            image: item.avatar_url
+            image: item.avatar_url,
           };
           if (item.full_name) {
             resultItem.description = htmlEscape(item.full_name);
@@ -34,15 +37,15 @@ export function initCompSearchUserBox() {
         if (allowEmailInput && items.length === 0 && looksLikeEmailAddressCheck.test(searchQuery)) {
           const resultItem = {
             title: searchQuery,
-            description: allowEmailDescription
+            description: allowEmailDescription,
           };
           items.push(resultItem);
         }
 
         return {results: items};
-      }
+      },
     },
     searchFields: ['login', 'full_name'],
-    showNoResults: false
+    showNoResults: false,
   });
 }
diff --git a/web_src/js/features/comp/WebHookEditor.js b/web_src/js/features/comp/WebHookEditor.js
index b7ca5a0fc..d74b59fd2 100644
--- a/web_src/js/features/comp/WebHookEditor.js
+++ b/web_src/js/features/comp/WebHookEditor.js
@@ -35,7 +35,7 @@ export function initCompWebHookEditor() {
 
   // Test delivery
   document.getElementById('test-delivery')?.addEventListener('click', async function () {
-    this.classList.add('loading', 'disabled');
+    this.classList.add('is-loading', 'disabled');
     await POST(this.getAttribute('data-link'));
     setTimeout(() => {
       window.location.href = this.getAttribute('data-redirect');
diff --git a/web_src/js/features/contextpopup.js b/web_src/js/features/contextpopup.js
index 51363b810..ce90f3e50 100644
--- a/web_src/js/features/contextpopup.js
+++ b/web_src/js/features/contextpopup.js
@@ -37,7 +37,7 @@ export function attachRefIssueContextPopup(refIssues) {
       interactiveBorder: 5,
       onShow: () => {
         el.firstChild.dispatchEvent(new CustomEvent('ce-load-context-popup', {detail: {owner, repo, index}}));
-      }
+      },
     });
   }
 }
diff --git a/web_src/js/features/contributors.js b/web_src/js/features/contributors.js
index 66185ac31..1d9cba5b9 100644
--- a/web_src/js/features/contributors.js
+++ b/web_src/js/features/contributors.js
@@ -18,7 +18,7 @@ export async function initRepoContributors() {
         loadingTitle: el.getAttribute('data-locale-loading-title'),
         loadingTitleFailed: el.getAttribute('data-locale-loading-title-failed'),
         loadingInfo: el.getAttribute('data-locale-loading-info'),
-      }
+      },
     });
     View.mount(el);
   } catch (err) {
diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js
index 2ac7d93cc..62581cf68 100644
--- a/web_src/js/features/eventsource.sharedworker.js
+++ b/web_src/js/features/eventsource.sharedworker.js
@@ -48,7 +48,7 @@ class Source {
     this.eventSource.addEventListener(eventType, (event) => {
       this.notifyClients({
         type: eventType,
-        data: event.data
+        data: event.data,
       });
     });
   }
diff --git a/web_src/js/features/imagediff.js b/web_src/js/features/imagediff.js
index 80b7e8338..53bf2109b 100644
--- a/web_src/js/features/imagediff.js
+++ b/web_src/js/features/imagediff.js
@@ -20,19 +20,19 @@ function getDefaultSvgBoundsIfUndefined(text, src) {
     if (img.width > 1 && img.width < MaxSize && img.height > 1 && img.height < MaxSize) {
       return {
         width: img.width,
-        height: img.height
+        height: img.height,
       };
     }
     if (svg.hasAttribute('viewBox')) {
       const viewBox = svg.viewBox.baseVal;
       return {
         width: DefaultSize,
-        height: DefaultSize * viewBox.width / viewBox.height
+        height: DefaultSize * viewBox.width / viewBox.height,
       };
     }
     return {
       width: DefaultSize,
-      height: DefaultSize
+      height: DefaultSize,
     };
   }
   return null;
@@ -42,20 +42,20 @@ export function initImageDiff() {
   function createContext(image1, image2) {
     const size1 = {
       width: image1 && image1.width || 0,
-      height: image1 && image1.height || 0
+      height: image1 && image1.height || 0,
     };
     const size2 = {
       width: image2 && image2.width || 0,
-      height: image2 && image2.height || 0
+      height: image2 && image2.height || 0,
     };
     const max = {
       width: Math.max(size2.width, size1.width),
-      height: Math.max(size2.height, size1.height)
+      height: Math.max(size2.height, size1.height),
     };
 
     return {
-      image1: $(image1),
-      image2: $(image2),
+      $image1: $(image1),
+      $image2: $(image2),
       size1,
       size2,
       max,
@@ -63,14 +63,14 @@ export function initImageDiff() {
         Math.floor(max.width - size1.width) / 2,
         Math.floor(max.height - size1.height) / 2,
         Math.floor(max.width - size2.width) / 2,
-        Math.floor(max.height - size2.height) / 2
-      ]
+        Math.floor(max.height - size2.height) / 2,
+      ],
     };
   }
 
   $('.image-diff:not([data-image-diff-loaded])').each(async function() {
     const $container = $(this);
-    $container.attr('data-image-diff-loaded', 'true');
+    this.setAttribute('data-image-diff-loaded', 'true');
 
     // the container may be hidden by "viewed" checkbox, so use the parent's width for reference
     const diffContainerWidth = Math.max($container.closest('.diff-file-box').width() - 300, 100);
@@ -79,12 +79,12 @@ export function initImageDiff() {
       path: this.getAttribute('data-path-after'),
       mime: this.getAttribute('data-mime-after'),
       $images: $container.find('img.image-after'), // matches 3 <img>
-      $boundsInfo: $container.find('.bounds-info-after')
+      $boundsInfo: $container.find('.bounds-info-after'),
     }, {
       path: this.getAttribute('data-path-before'),
       mime: this.getAttribute('data-mime-before'),
       $images: $container.find('img.image-before'), // matches 3 <img>
-      $boundsInfo: $container.find('.bounds-info-before')
+      $boundsInfo: $container.find('.bounds-info-before'),
     }];
 
     await Promise.all(imageInfos.map(async (info) => {
@@ -98,8 +98,10 @@ export function initImageDiff() {
         const text = await resp.text();
         const bounds = getDefaultSvgBoundsIfUndefined(text, info.path);
         if (bounds) {
-          info.$images.attr('width', bounds.width);
-          info.$images.attr('height', bounds.height);
+          info.$images.each(function() {
+            this.setAttribute('width', bounds.width);
+            this.setAttribute('height', bounds.height);
+          });
           hideElem(info.$boundsInfo);
         }
       }
@@ -122,35 +124,36 @@ export function initImageDiff() {
         factor = (diffContainerWidth - 24) / 2 / sizes.max.width;
       }
 
-      const widthChanged = sizes.image1.length !== 0 && sizes.image2.length !== 0 && sizes.image1[0].naturalWidth !== sizes.image2[0].naturalWidth;
-      const heightChanged = sizes.image1.length !== 0 && sizes.image2.length !== 0 && sizes.image1[0].naturalHeight !== sizes.image2[0].naturalHeight;
-      if (sizes.image1.length !== 0) {
-        $container.find('.bounds-info-after .bounds-info-width').text(`${sizes.image1[0].naturalWidth}px`).addClass(widthChanged ? 'green' : '');
-        $container.find('.bounds-info-after .bounds-info-height').text(`${sizes.image1[0].naturalHeight}px`).addClass(heightChanged ? 'green' : '');
+      const widthChanged = sizes.$image1.length !== 0 && sizes.$image2.length !== 0 && sizes.$image1[0].naturalWidth !== sizes.$image2[0].naturalWidth;
+      const heightChanged = sizes.$image1.length !== 0 && sizes.$image2.length !== 0 && sizes.$image1[0].naturalHeight !== sizes.$image2[0].naturalHeight;
+      if (sizes.$image1.length !== 0) {
+        $container.find('.bounds-info-after .bounds-info-width').text(`${sizes.$image1[0].naturalWidth}px`).addClass(widthChanged ? 'green' : '');
+        $container.find('.bounds-info-after .bounds-info-height').text(`${sizes.$image1[0].naturalHeight}px`).addClass(heightChanged ? 'green' : '');
       }
-      if (sizes.image2.length !== 0) {
-        $container.find('.bounds-info-before .bounds-info-width').text(`${sizes.image2[0].naturalWidth}px`).addClass(widthChanged ? 'red' : '');
-        $container.find('.bounds-info-before .bounds-info-height').text(`${sizes.image2[0].naturalHeight}px`).addClass(heightChanged ? 'red' : '');
+      if (sizes.$image2.length !== 0) {
+        $container.find('.bounds-info-before .bounds-info-width').text(`${sizes.$image2[0].naturalWidth}px`).addClass(widthChanged ? 'red' : '');
+        $container.find('.bounds-info-before .bounds-info-height').text(`${sizes.$image2[0].naturalHeight}px`).addClass(heightChanged ? 'red' : '');
       }
 
-      sizes.image1.css({
-        width: sizes.size1.width * factor,
-        height: sizes.size1.height * factor
-      });
-      sizes.image1.parent().css({
-        margin: `10px auto`,
-        width: sizes.size1.width * factor + 2,
-        height: sizes.size1.height * factor + 2
-      });
-      sizes.image2.css({
-        width: sizes.size2.width * factor,
-        height: sizes.size2.height * factor
-      });
-      sizes.image2.parent().css({
-        margin: `10px auto`,
-        width: sizes.size2.width * factor + 2,
-        height: sizes.size2.height * factor + 2
-      });
+      const image1 = sizes.$image1[0];
+      if (image1) {
+        const container = image1.parentNode;
+        image1.style.width = `${sizes.size1.width * factor}px`;
+        image1.style.height = `${sizes.size1.height * factor}px`;
+        container.style.margin = '10px auto';
+        container.style.width = `${sizes.size1.width * factor + 2}px`;
+        container.style.height = `${sizes.size1.height * factor + 2}px`;
+      }
+
+      const image2 = sizes.$image2[0];
+      if (image2) {
+        const container = image2.parentNode;
+        image2.style.width = `${sizes.size2.width * factor}px`;
+        image2.style.height = `${sizes.size2.height * factor}px`;
+        container.style.margin = '10px auto';
+        container.style.width = `${sizes.size2.width * factor + 2}px`;
+        container.style.height = `${sizes.size2.height * factor + 2}px`;
+      }
     }
 
     function initSwipe(sizes) {
@@ -159,36 +162,39 @@ export function initImageDiff() {
         factor = (diffContainerWidth - 12) / sizes.max.width;
       }
 
-      sizes.image1.css({
-        width: sizes.size1.width * factor,
-        height: sizes.size1.height * factor
-      });
-      sizes.image1.parent().css({
-        margin: `0px ${sizes.ratio[0] * factor}px`,
-        width: sizes.size1.width * factor + 2,
-        height: sizes.size1.height * factor + 2
-      });
-      sizes.image1.parent().parent().css({
-        padding: `${sizes.ratio[1] * factor}px 0 0 0`,
-        width: sizes.max.width * factor + 2
-      });
-      sizes.image2.css({
-        width: sizes.size2.width * factor,
-        height: sizes.size2.height * factor
-      });
-      sizes.image2.parent().css({
-        margin: `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`,
-        width: sizes.size2.width * factor + 2,
-        height: sizes.size2.height * factor + 2
-      });
-      sizes.image2.parent().parent().css({
-        width: sizes.max.width * factor + 2,
-        height: sizes.max.height * factor + 2
-      });
-      $container.find('.diff-swipe').css({
-        width: sizes.max.width * factor + 2,
-        height: sizes.max.height * factor + 30 /* extra height for inner "position: absolute" elements */,
-      });
+      const image1 = sizes.$image1[0];
+      if (image1) {
+        const container = image1.parentNode;
+        const swipeFrame = container.parentNode;
+        image1.style.width = `${sizes.size1.width * factor}px`;
+        image1.style.height = `${sizes.size1.height * factor}px`;
+        container.style.margin = `0px ${sizes.ratio[0] * factor}px`;
+        container.style.width = `${sizes.size1.width * factor + 2}px`;
+        container.style.height = `${sizes.size1.height * factor + 2}px`;
+        swipeFrame.style.padding = `${sizes.ratio[1] * factor}px 0 0 0`;
+        swipeFrame.style.width = `${sizes.max.width * factor + 2}px`;
+      }
+
+      const image2 = sizes.$image2[0];
+      if (image2) {
+        const container = image2.parentNode;
+        const swipeFrame = container.parentNode;
+        image2.style.width = `${sizes.size2.width * factor}px`;
+        image2.style.height = `${sizes.size2.height * factor}px`;
+        container.style.margin = `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`;
+        container.style.width = `${sizes.size2.width * factor + 2}px`;
+        container.style.height = `${sizes.size2.height * factor + 2}px`;
+        swipeFrame.style.width = `${sizes.max.width * factor + 2}px`;
+        swipeFrame.style.height = `${sizes.max.height * factor + 2}px`;
+      }
+
+      // extra height for inner "position: absolute" elements
+      const swipe = $container.find('.diff-swipe')[0];
+      if (swipe) {
+        swipe.style.width = `${sizes.max.width * factor + 2}px`;
+        swipe.style.height = `${sizes.max.height * factor + 30}px`;
+      }
+
       $container.find('.swipe-bar').on('mousedown', function(e) {
         e.preventDefault();
 
@@ -200,13 +206,9 @@ export function initImageDiff() {
           e2.preventDefault();
 
           const value = Math.max(0, Math.min(e2.clientX - $swipeFrame.offset().left, width));
+          $swipeBar[0].style.left = `${value}px`;
+          $container.find('.swipe-container')[0].style.width = `${$swipeFrame.width() - value}px`;
 
-          $swipeBar.css({
-            left: value
-          });
-          $container.find('.swipe-container').css({
-            width: $swipeFrame.width() - value
-          });
           $(document).on('mouseup.diff-swipe', () => {
             $(document).off('.diff-swipe');
           });
@@ -220,38 +222,39 @@ export function initImageDiff() {
         factor = (diffContainerWidth - 12) / sizes.max.width;
       }
 
-      sizes.image1.css({
-        width: sizes.size1.width * factor,
-        height: sizes.size1.height * factor
-      });
-      sizes.image2.css({
-        width: sizes.size2.width * factor,
-        height: sizes.size2.height * factor
-      });
-      sizes.image1.parent().css({
-        margin: `${sizes.ratio[1] * factor}px ${sizes.ratio[0] * factor}px`,
-        width: sizes.size1.width * factor + 2,
-        height: sizes.size1.height * factor + 2
-      });
-      sizes.image2.parent().css({
-        margin: `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`,
-        width: sizes.size2.width * factor + 2,
-        height: sizes.size2.height * factor + 2
-      });
+      const image1 = sizes.$image1[0];
+      if (image1) {
+        const container = image1.parentNode;
+        image1.style.width = `${sizes.size1.width * factor}px`;
+        image1.style.height = `${sizes.size1.height * factor}px`;
+        container.style.margin = `${sizes.ratio[1] * factor}px ${sizes.ratio[0] * factor}px`;
+        container.style.width = `${sizes.size1.width * factor + 2}px`;
+        container.style.height = `${sizes.size1.height * factor + 2}px`;
+      }
 
-      // some inner elements are `position: absolute`, so the container's height must be large enough
-      // the "css(width, height)" is somewhat hacky and not easy to understand, it could be improved in the future
-      sizes.image2.parent().parent().css({
-        width: sizes.max.width * factor + 2,
-        height: sizes.max.height * factor + 2,
-      });
+      const image2 = sizes.$image2[0];
+      if (image2) {
+        const container = image2.parentNode;
+        const overlayFrame = container.parentNode;
+        image2.style.width = `${sizes.size2.width * factor}px`;
+        image2.style.height = `${sizes.size2.height * factor}px`;
+        container.style.margin = `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`;
+        container.style.width = `${sizes.size2.width * factor + 2}px`;
+        container.style.height = `${sizes.size2.height * factor + 2}px`;
 
-      const $range = $container.find("input[type='range']");
-      const onInput = () => sizes.image1.parent().css({
-        opacity: $range.val() / 100
-      });
-      $range.on('input', onInput);
-      onInput();
+        // some inner elements are `position: absolute`, so the container's height must be large enough
+        overlayFrame.style.width = `${sizes.max.width * factor + 2}px`;
+        overlayFrame.style.height = `${sizes.max.height * factor + 2}px`;
+      }
+
+      const rangeInput = $container[0].querySelector('input[type="range"]');
+      function updateOpacity() {
+        if (sizes?.$image1?.[0]) {
+          sizes.$image1[0].parentNode.style.opacity = `${rangeInput.value / 100}`;
+        }
+      }
+      rangeInput?.addEventListener('input', updateOpacity);
+      updateOpacity();
     }
   });
 }
diff --git a/web_src/js/features/install.js b/web_src/js/features/install.js
index 1826ff7cd..0c2246b93 100644
--- a/web_src/js/features/install.js
+++ b/web_src/js/features/install.js
@@ -19,7 +19,7 @@ function initPreInstall() {
   const defaultDbHosts = {
     mysql: '127.0.0.1:3306',
     postgres: '127.0.0.1:5432',
-    mssql: '127.0.0.1:1433'
+    mssql: '127.0.0.1:1433',
   };
 
   const dbHost = document.getElementById('db_host');
diff --git a/web_src/js/features/org-team.js b/web_src/js/features/org-team.js
index 6ae3a90f4..2236bc58b 100644
--- a/web_src/js/features/org-team.js
+++ b/web_src/js/features/org-team.js
@@ -26,14 +26,14 @@ export function initOrgTeamSearchRepoBox() {
         $.each(response.data, (_i, item) => {
           items.push({
             title: item.repository.full_name.split('/')[1],
-            description: item.repository.full_name
+            description: item.repository.full_name,
           });
         });
 
         return {results: items};
-      }
+      },
     },
     searchFields: ['full_name'],
-    showNoResults: false
+    showNoResults: false,
   });
 }
diff --git a/web_src/js/features/recent-commits.js b/web_src/js/features/recent-commits.js
index ded10d39b..030c251a0 100644
--- a/web_src/js/features/recent-commits.js
+++ b/web_src/js/features/recent-commits.js
@@ -11,7 +11,7 @@ export async function initRepoRecentCommits() {
         loadingTitle: el.getAttribute('data-locale-loading-title'),
         loadingTitleFailed: el.getAttribute('data-locale-loading-title-failed'),
         loadingInfo: el.getAttribute('data-locale-loading-info'),
-      }
+      },
     });
     View.mount(el);
   } catch (err) {
diff --git a/web_src/js/features/repo-code.js b/web_src/js/features/repo-code.js
index c4a81ea16..08fae763b 100644
--- a/web_src/js/features/repo-code.js
+++ b/web_src/js/features/repo-code.js
@@ -116,7 +116,7 @@ function showLineButton() {
       tippy.popper.addEventListener('click', () => {
         tippy.hide();
       }, {once: true});
-    }
+    },
   });
 }
 
diff --git a/web_src/js/features/repo-common.js b/web_src/js/features/repo-common.js
index a8221bbea..2c5746c73 100644
--- a/web_src/js/features/repo-common.js
+++ b/web_src/js/features/repo-common.js
@@ -3,18 +3,20 @@ import {hideElem, showElem} from '../utils/dom.js';
 import {POST} from '../modules/fetch.js';
 
 async function getArchive($target, url, first) {
+  const dropdownBtn = $target[0].closest('.ui.dropdown.button');
+
   try {
+    dropdownBtn.classList.add('is-loading');
     const response = await POST(url);
     if (response.status === 200) {
       const data = await response.json();
       if (!data) {
         // XXX Shouldn't happen?
-        $target.closest('.dropdown').children('i').removeClass('loading');
+        dropdownBtn.classList.remove('is-loading');
         return;
       }
 
       if (!data.complete) {
-        $target.closest('.dropdown').children('i').addClass('loading');
         // Wait for only three quarters of a second initially, in case it's
         // quickly archived.
         setTimeout(() => {
@@ -22,19 +24,19 @@ async function getArchive($target, url, first) {
         }, first ? 750 : 2000);
       } else {
         // We don't need to continue checking.
-        $target.closest('.dropdown').children('i').removeClass('loading');
+        dropdownBtn.classList.remove('is-loading');
         window.location.href = url;
       }
     }
   } catch {
-    $target.closest('.dropdown').children('i').removeClass('loading');
+    dropdownBtn.classList.remove('is-loading');
   }
 }
 
 export function initRepoArchiveLinks() {
   $('.archive-link').on('click', function (event) {
     event.preventDefault();
-    const url = $(this).attr('href');
+    const url = this.getAttribute('href');
     if (!url) return;
     getArchive($(event.target), url, true);
   });
@@ -76,14 +78,16 @@ export function initRepoCommonBranchOrTagDropdown(selector) {
 
 export function initRepoCommonFilterSearchDropdown(selector) {
   const $dropdown = $(selector);
+  if (!$dropdown.length) return;
+
   $dropdown.dropdown({
     fullTextSearch: 'exact',
     selectOnKeydown: false,
     onChange(_text, _value, $choice) {
-      if ($choice.attr('data-url')) {
-        window.location.href = $choice.attr('data-url');
+      if ($choice[0].getAttribute('data-url')) {
+        window.location.href = $choice[0].getAttribute('data-url');
       }
     },
-    message: {noResults: $dropdown.attr('data-no-results')},
+    message: {noResults: $dropdown[0].getAttribute('data-no-results')},
   });
 }
diff --git a/web_src/js/features/repo-diff-commit.js b/web_src/js/features/repo-diff-commit.js
index 3d4f0f677..f0466f932 100644
--- a/web_src/js/features/repo-diff-commit.js
+++ b/web_src/js/features/repo-diff-commit.js
@@ -39,7 +39,7 @@ function addLink(parent, href, text, tooltip) {
   link.href = href;
   link.textContent = text;
   if (tooltip) {
-    link.classList.add('gt-border-secondary', 'gt-rounded');
+    link.classList.add('tw-border', 'tw-border-secondary', 'tw-rounded');
     link.setAttribute('data-tooltip-content', tooltip);
   }
   parent.append(link);
diff --git a/web_src/js/features/repo-diff.js b/web_src/js/features/repo-diff.js
index ffe3fada8..2feb2597e 100644
--- a/web_src/js/features/repo-diff.js
+++ b/web_src/js/features/repo-diff.js
@@ -13,16 +13,20 @@ import {POST, GET} from '../modules/fetch.js';
 const {pageData, i18n} = window.config;
 
 function initRepoDiffReviewButton() {
-  const $reviewBox = $('#review-box');
-  const $counter = $reviewBox.find('.review-comments-counter');
+  const reviewBox = document.getElementById('review-box');
+  if (!reviewBox) return;
+
+  const $reviewBox = $(reviewBox);
+  const counter = reviewBox.querySelector('.review-comments-counter');
+  if (!counter) return;
 
   $(document).on('click', 'button[name="pending_review"]', (e) => {
     const $form = $(e.target).closest('form');
     // Watch for the form's submit event.
     $form.on('submit', () => {
-      const num = parseInt($counter.attr('data-pending-comment-number')) + 1 || 1;
-      $counter.attr('data-pending-comment-number', num);
-      $counter.text(num);
+      const num = parseInt(counter.getAttribute('data-pending-comment-number')) + 1 || 1;
+      counter.setAttribute('data-pending-comment-number', num);
+      counter.textContent = num;
       // Force the browser to reflow the DOM. This is to ensure that the browser replay the animation
       $reviewBox.removeClass('pulse');
       $reviewBox.width();
@@ -67,7 +71,7 @@ function initRepoDiffConversationForm() {
         formData.append(submitter.name, submitter.value);
       }
 
-      const response = await POST($form.attr('action'), {data: formData});
+      const response = await POST(e.target.getAttribute('action'), {data: formData});
       const $newConversationHolder = $(await response.text());
       const {path, side, idx} = $newConversationHolder.data();
 
@@ -120,7 +124,7 @@ export function initRepoDiffConversationNav() {
     const index = $conversations.index($conversation);
     const previousIndex = index > 0 ? index - 1 : $conversations.length - 1;
     const $previousConversation = $conversations.eq(previousIndex);
-    const anchor = $previousConversation.find('.comment').first().attr('id');
+    const anchor = $previousConversation.find('.comment').first()[0].getAttribute('id');
     window.location.href = `#${anchor}`;
   });
   $(document).on('click', '.next-conversation', (e) => {
@@ -129,7 +133,7 @@ export function initRepoDiffConversationNav() {
     const index = $conversations.index($conversation);
     const nextIndex = index < $conversations.length - 1 ? index + 1 : 0;
     const $nextConversation = $conversations.eq(nextIndex);
-    const anchor = $nextConversation.find('.comment').first().attr('id');
+    const anchor = $nextConversation.find('.comment').first()[0].getAttribute('id');
     window.location.href = `#${anchor}`;
   });
 }
@@ -175,8 +179,7 @@ function initRepoDiffShowMore() {
   $(document).on('click', 'a#diff-show-more-files', (e) => {
     e.preventDefault();
 
-    const $target = $(e.target);
-    const linkLoadMore = $target.attr('data-href');
+    const linkLoadMore = e.target.getAttribute('data-href');
     loadMoreFiles(linkLoadMore);
   });
 
diff --git a/web_src/js/features/repo-editor.js b/web_src/js/features/repo-editor.js
index ba00573c0..1ab0a5786 100644
--- a/web_src/js/features/repo-editor.js
+++ b/web_src/js/features/repo-editor.js
@@ -72,7 +72,7 @@ export function initRepoEditor() {
       hideElem($('.quick-pull-branch-name'));
       document.querySelector('.quick-pull-branch-name input').required = false;
     }
-    $('#commit-button').text($(this).attr('button_text'));
+    $('#commit-button').text(this.getAttribute('button_text'));
   });
 
   const joinTreePath = ($fileNameEl) => {
diff --git a/web_src/js/features/repo-graph.js b/web_src/js/features/repo-graph.js
index 4fbf95b9d..f2c0d78f3 100644
--- a/web_src/js/features/repo-graph.js
+++ b/web_src/js/features/repo-graph.js
@@ -18,13 +18,13 @@ export function initRepoGraphGit() {
       window.history.replaceState({}, '', window.location.pathname);
     }
     $('.pagination a').each((_, that) => {
-      const href = $(that).attr('href');
+      const href = that.getAttribute('href');
       if (!href) return;
       const url = new URL(href, window.location);
       const params = url.searchParams;
       params.set('mode', 'monochrome');
       url.search = `?${params.toString()}`;
-      $(that).attr('href', url.href);
+      that.setAttribute('href', url.href);
     });
   });
   $('#flow-color-colored').on('click', () => {
@@ -32,13 +32,13 @@ export function initRepoGraphGit() {
     $('#flow-color-monochrome').removeClass('active');
     $('#git-graph-container').addClass('colored').removeClass('monochrome');
     $('.pagination a').each((_, that) => {
-      const href = $(that).attr('href');
+      const href = that.getAttribute('href');
       if (!href) return;
       const url = new URL(href, window.location);
       const params = url.searchParams;
       params.delete('mode');
       url.search = `?${params.toString()}`;
-      $(that).attr('href', url.href);
+      that.setAttribute('href', url.href);
     });
     const params = new URLSearchParams(window.location.search);
     params.delete('mode');
diff --git a/web_src/js/features/repo-home.js b/web_src/js/features/repo-home.js
index 50f324d78..6ac7b96b9 100644
--- a/web_src/js/features/repo-home.js
+++ b/web_src/js/features/repo-home.js
@@ -146,7 +146,7 @@ export function initRepoTopicBar() {
       addedValue = addedValue.toLowerCase().trim();
       $($addedChoice).attr('data-value', addedValue);
       $($addedChoice).attr('data-text', addedValue);
-    }
+    },
   });
 
   $.fn.form.settings.rules.validateTopic = function (_values, regExp) {
@@ -168,14 +168,14 @@ export function initRepoTopicBar() {
           {
             type: 'validateTopic',
             value: /^\s*[a-z0-9][-.a-z0-9]{0,35}\s*$/,
-            prompt: topicPrompts.formatPrompt
+            prompt: topicPrompts.formatPrompt,
           },
           {
             type: 'maxCount[25]',
-            prompt: topicPrompts.countPrompt
-          }
-        ]
+            prompt: topicPrompts.countPrompt,
+          },
+        ],
       },
-    }
+    },
   });
 }
diff --git a/web_src/js/features/repo-issue-content.js b/web_src/js/features/repo-issue-content.js
index 9e2b77373..e7768b066 100644
--- a/web_src/js/features/repo-issue-content.js
+++ b/web_src/js/features/repo-issue-content.js
@@ -16,7 +16,7 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
   $dialog = $(`
 <div class="ui modal content-history-detail-dialog">
   ${svg('octicon-x', 16, 'close icon inside')}
-  <div class="header gt-df gt-ac gt-sb">
+  <div class="header tw-flex tw-items-center tw-justify-between">
     <div>${itemTitleHtml}</div>
     <div class="ui dropdown dialog-header-options gt-mr-5 gt-hidden">
       ${i18nTextOptions}
@@ -60,7 +60,7 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
     },
     onHide() {
       $(this).dropdown('clear', true);
-    }
+    },
   });
   $dialog.modal({
     async onShow() {
diff --git a/web_src/js/features/repo-issue-list.js b/web_src/js/features/repo-issue-list.js
index 48b1555c8..4bdd5e5a8 100644
--- a/web_src/js/features/repo-issue-list.js
+++ b/web_src/js/features/repo-issue-list.js
@@ -9,6 +9,7 @@ import {DELETE, POST} from '../modules/fetch.js';
 
 function initRepoIssueListCheckboxes() {
   const issueSelectAll = document.querySelector('.issue-checkbox-all');
+  if (!issueSelectAll) return; // logged out state
   const issueCheckboxes = document.querySelectorAll('.issue-checkbox');
 
   const syncIssueSelectionState = () => {
@@ -92,9 +93,9 @@ function initRepoIssueListAuthorDropdown() {
   const $searchDropdown = $('.user-remote-search');
   if (!$searchDropdown.length) return;
 
-  let searchUrl = $searchDropdown.attr('data-search-url');
-  const actionJumpUrl = $searchDropdown.attr('data-action-jump-url');
-  const selectedUserId = $searchDropdown.attr('data-selected-user-id');
+  let searchUrl = $searchDropdown[0].getAttribute('data-search-url');
+  const actionJumpUrl = $searchDropdown[0].getAttribute('data-action-jump-url');
+  const selectedUserId = $searchDropdown[0].getAttribute('data-selected-user-id');
   if (!searchUrl.includes('?')) searchUrl += '?';
 
   $searchDropdown.dropdown('setting', {
@@ -107,7 +108,7 @@ function initRepoIssueListAuthorDropdown() {
         // the content is provided by backend IssuePosters handler
         const processedResults = []; // to be used by dropdown to generate menu items
         for (const item of resp.results) {
-          let html = `<img class="ui avatar gt-vm" src="${htmlEscape(item.avatar_link)}" aria-hidden="true" alt="" width="20" height="20"><span class="gt-ellipsis">${htmlEscape(item.username)}</span>`;
+          let html = `<img class="ui avatar tw-align-middle" src="${htmlEscape(item.avatar_link)}" aria-hidden="true" alt="" width="20" height="20"><span class="gt-ellipsis">${htmlEscape(item.username)}</span>`;
           if (item.full_name) html += `<span class="search-fullname gt-ml-3">${htmlEscape(item.full_name)}</span>`;
           processedResults.push({value: item.user_id, name: html});
         }
diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js
index bca062bcc..bf4ec1537 100644
--- a/web_src/js/features/repo-issue.js
+++ b/web_src/js/features/repo-issue.js
@@ -43,14 +43,14 @@ export function initRepoIssueTimeTracking() {
 
 async function updateDeadline(deadlineString) {
   hideElem($('#deadline-err-invalid-date'));
-  $('#deadline-loader').addClass('loading');
+  $('#deadline-loader').addClass('is-loading');
 
   let realDeadline = null;
   if (deadlineString !== '') {
     const newDate = Date.parse(deadlineString);
 
     if (Number.isNaN(newDate)) {
-      $('#deadline-loader').removeClass('loading');
+      $('#deadline-loader').removeClass('is-loading');
       showElem($('#deadline-err-invalid-date'));
       return false;
     }
@@ -59,7 +59,7 @@ async function updateDeadline(deadlineString) {
 
   try {
     const response = await POST($('#update-issue-deadline-form').attr('action'), {
-      data: {due_date: realDeadline}
+      data: {due_date: realDeadline},
     });
 
     if (response.ok) {
@@ -69,7 +69,7 @@ async function updateDeadline(deadlineString) {
     }
   } catch (error) {
     console.error(error);
-    $('#deadline-loader').removeClass('loading');
+    $('#deadline-loader').removeClass('is-loading');
     showElem($('#deadline-err-invalid-date'));
   }
 }
@@ -162,7 +162,8 @@ export function initRepoIssueCommentDelete() {
         const response = await POST($this.data('url'));
         if (!response.ok) throw new Error('Failed to delete comment');
         const $conversationHolder = $this.closest('.conversation-holder');
-
+        const $parentTimelineItem = $this.closest('.timeline-item');
+        const $parentTimelineGroup = $this.closest('.timeline-item-group');
         // Check if this was a pending comment.
         if ($conversationHolder.find('.pending-label').length) {
           const $counter = $('#review-box .review-comments-counter');
@@ -185,6 +186,11 @@ export function initRepoIssueCommentDelete() {
           }
           $conversationHolder.remove();
         }
+        // Check if there is no review content, move the time avatar upward to avoid overlapping the content below.
+        if (!$parentTimelineGroup.find('.timeline-item.comment').length && !$parentTimelineItem.find('.conversation-holder').length) {
+          const $timelineAvatar = $parentTimelineGroup.find('.timeline-avatar');
+          $timelineAvatar.removeClass('timeline-avatar-offset');
+        }
       } catch (error) {
         console.error(error);
       }
@@ -231,14 +237,14 @@ export function initRepoPullRequestUpdate() {
     e.preventDefault();
     const $this = $(this);
     const redirect = $this.data('redirect');
-    $this.addClass('loading');
+    $this.addClass('is-loading');
     let response;
     try {
       response = await POST($this.data('do'));
     } catch (error) {
       console.error(error);
     } finally {
-      $this.removeClass('loading');
+      $this.removeClass('is-loading');
     }
     let data;
     try {
@@ -262,7 +268,7 @@ export function initRepoPullRequestUpdate() {
         $pullUpdateButton.find('.button-text').text($choice.text());
         $pullUpdateButton.data('do', $url);
       }
-    }
+    },
   });
 }
 
@@ -310,7 +316,7 @@ export function initRepoIssueReferenceRepositorySearch() {
           $.each(response.data, (_r, repo) => {
             filteredResponse.results.push({
               name: htmlEscape(repo.repository.full_name),
-              value: repo.repository.full_name
+              value: repo.repository.full_name,
             });
           });
           return filteredResponse;
@@ -321,7 +327,7 @@ export function initRepoIssueReferenceRepositorySearch() {
         const $form = $choice.closest('form');
         $form.attr('action', `${appSubUrl}/${_text}/issues/new`);
       },
-      fullTextSearch: true
+      fullTextSearch: true,
     });
 }
 
@@ -437,7 +443,7 @@ export function initRepoPullRequestReview() {
         }
         window.scrollTo({
           top: $commentDiv.offset().top - offset,
-          behavior: 'instant'
+          behavior: 'instant',
         });
       }
     }
@@ -655,7 +661,7 @@ export function initRepoIssueBranchSelect() {
     // Replace branch name to keep translation from HTML template
     $selectionTextField.html($selectionTextField.html().replace(
       `${baseName}:${branchNameOld}`,
-      `${baseName}:${branchNameNew}`
+      `${baseName}:${branchNameNew}`,
     ));
     $selectionTextField.data('branch', branchNameNew); // update branch name in setting
   };
@@ -689,7 +695,7 @@ export function initIssueTemplateCommentEditors($commentForm) {
     const editor = await initComboMarkdownEditor($markdownEditor, {
       onContentChanged: (editor) => {
         $formField.val(editor.value());
-      }
+      },
     });
 
     $formField.on('focus', async () => {
diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js
index 6155b3a5d..33d8ab291 100644
--- a/web_src/js/features/repo-legacy.js
+++ b/web_src/js/features/repo-legacy.js
@@ -389,7 +389,7 @@ async function onEditContent(event) {
               dz.emit('complete', attachment);
               dz.files.push(attachment);
               fileUuidDict[attachment.uuid] = {submitted: true};
-              $dropzone.find(`img[src='${imgSrc}']`).css('max-width', '100%');
+              $dropzone.find(`img[src='${imgSrc}']`)[0].style.maxWidth = '100%';
               const $input = $(`<input id="${attachment.uuid}" name="files" type="hidden">`).val(attachment.uuid);
               $dropzone.find('.files').append($input);
             }
@@ -436,7 +436,7 @@ async function onEditContent(event) {
       const $content = $segment;
       if (!$content.find('.dropzone-attachments').length) {
         if (data.attachments !== '') {
-          $content[0].append(data.attachments);
+          $content[0].insertAdjacentHTML('beforeend', data.attachments);
         }
       } else if (data.attachments === '') {
         $content.find('.dropzone-attachments').remove();
diff --git a/web_src/js/features/repo-projects.js b/web_src/js/features/repo-projects.js
index 1f86711ab..fc688bb69 100644
--- a/web_src/js/features/repo-projects.js
+++ b/web_src/js/features/repo-projects.js
@@ -33,7 +33,7 @@ async function moveIssue({item, from, to, oldIndex}) {
 
   const columnSorting = {
     issues: Array.from(columnCards, (card, i) => ({
-      issueID: parseInt($(card).attr('data-issue')),
+      issueID: parseInt(card.getAttribute('data-issue')),
       sorting: i,
     })),
   };
@@ -72,7 +72,7 @@ async function initRepoProjectSortable() {
             await PUT($(column).data('url'), {
               data: {
                 sorting: i,
-                color: rgbToHex($(column).css('backgroundColor')),
+                color: rgbToHex(window.getComputedStyle($(column)[0]).backgroundColor),
               },
             });
           } catch (error) {
@@ -111,8 +111,9 @@ export function initRepoProject() {
     const $projectColorInput = $(this).find('#new_project_column_color');
     const $boardColumn = $(this).closest('.project-column');
 
-    if ($boardColumn.css('backgroundColor')) {
-      setLabelColor($projectHeader, rgbToHex($boardColumn.css('backgroundColor')));
+    const bgColor = $boardColumn[0].style.backgroundColor;
+    if (bgColor) {
+      setLabelColor($projectHeader, rgbToHex(bgColor));
     }
 
     $(this).find('.edit-project-column-button').on('click', async function (e) {
@@ -133,7 +134,7 @@ export function initRepoProject() {
         if ($projectColorInput.val()) {
           setLabelColor($projectHeader, $projectColorInput.val());
         }
-        $boardColumn.attr('style', `background: ${$projectColorInput.val()}!important`);
+        $boardColumn[0].style = `background: ${$projectColorInput.val()} !important`;
         $('.ui.modal').modal('hide');
       }
     });
@@ -158,9 +159,9 @@ export function initRepoProject() {
   });
 
   $('.show-delete-project-column-modal').each(function () {
-    const $deleteColumnModal = $(`${$(this).attr('data-modal')}`);
+    const $deleteColumnModal = $(`${this.getAttribute('data-modal')}`);
     const $deleteColumnButton = $deleteColumnModal.find('.actions > .ok.button');
-    const deleteUrl = $(this).attr('data-url');
+    const deleteUrl = this.getAttribute('data-url');
 
     $deleteColumnButton.on('click', async (e) => {
       e.preventDefault();
diff --git a/web_src/js/features/repo-settings.js b/web_src/js/features/repo-settings.js
index 0418f3a14..dc1db8ab2 100644
--- a/web_src/js/features/repo-settings.js
+++ b/web_src/js/features/repo-settings.js
@@ -8,22 +8,22 @@ const {appSubUrl, csrfToken} = window.config;
 
 export function initRepoSettingsCollaboration() {
   // Change collaborator access mode
-  $('.page-content.repository .ui.dropdown.access-mode').each((_, e) => {
-    const $dropdown = $(e);
+  $('.page-content.repository .ui.dropdown.access-mode').each((_, el) => {
+    const $dropdown = $(el);
     const $text = $dropdown.find('> .text');
     $dropdown.dropdown({
       async action(_text, value) {
-        const lastValue = $dropdown.attr('data-last-value');
+        const lastValue = el.getAttribute('data-last-value');
         try {
-          $dropdown.attr('data-last-value', value);
+          el.setAttribute('data-last-value', value);
           $dropdown.dropdown('hide');
           const data = new FormData();
-          data.append('uid', $dropdown.attr('data-uid'));
+          data.append('uid', el.getAttribute('data-uid'));
           data.append('mode', value);
-          await POST($dropdown.attr('data-url'), {data});
+          await POST(el.getAttribute('data-url'), {data});
         } catch {
           $text.text('(error)'); // prevent from misleading users when error occurs
-          $dropdown.attr('data-last-value', lastValue);
+          el.setAttribute('data-last-value', lastValue);
         }
       },
       onChange(_value, text, _$choice) {
@@ -32,39 +32,41 @@ export function initRepoSettingsCollaboration() {
       onHide() {
         // set to the really selected value, defer to next tick to make sure `action` has finished its work because the calling order might be onHide -> action
         setTimeout(() => {
-          const $item = $dropdown.dropdown('get item', $dropdown.attr('data-last-value'));
+          const $item = $dropdown.dropdown('get item', el.getAttribute('data-last-value'));
           if ($item) {
-            $dropdown.dropdown('set selected', $dropdown.attr('data-last-value'));
+            $dropdown.dropdown('set selected', el.getAttribute('data-last-value'));
           } else {
             $text.text('(none)'); // prevent from misleading users when the access mode is undefined
           }
         }, 0);
-      }
+      },
     });
   });
 }
 
 export function initRepoSettingSearchTeamBox() {
-  const $searchTeamBox = $('#search-team-box');
-  $searchTeamBox.search({
+  const searchTeamBox = document.getElementById('search-team-box');
+  if (!searchTeamBox) return;
+
+  $(searchTeamBox).search({
     minCharacters: 2,
     apiSettings: {
-      url: `${appSubUrl}/org/${$searchTeamBox.attr('data-org-name')}/teams/-/search?q={query}`,
+      url: `${appSubUrl}/org/${searchTeamBox.getAttribute('data-org-name')}/teams/-/search?q={query}`,
       headers: {'X-Csrf-Token': csrfToken},
       onResponse(response) {
         const items = [];
         $.each(response.data, (_i, item) => {
           items.push({
             title: item.name,
-            description: `${item.permission} access` // TODO: translate this string
+            description: `${item.permission} access`, // TODO: translate this string
           });
         });
 
         return {results: items};
-      }
+      },
     },
     searchFields: ['name', 'description'],
-    showNoResults: false
+    showNoResults: false,
   });
 }
 
@@ -77,11 +79,11 @@ export function initRepoSettingGitHook() {
 export function initRepoSettingBranches() {
   if (!$('.repository.settings.branches').length) return;
   $('.toggle-target-enabled').on('change', function () {
-    const $target = $($(this).attr('data-target'));
+    const $target = $(this.getAttribute('data-target'));
     $target.toggleClass('disabled', !this.checked);
   });
   $('.toggle-target-disabled').on('change', function () {
-    const $target = $($(this).attr('data-target'));
+    const $target = $(this.getAttribute('data-target'));
     if (this.checked) $target.addClass('disabled'); // only disable, do not auto enable
   });
   $('#dismiss_stale_approvals').on('change', function () {
diff --git a/web_src/js/features/repo-template.js b/web_src/js/features/repo-template.js
index 1e83e7478..5f63e8b3b 100644
--- a/web_src/js/features/repo-template.js
+++ b/web_src/js/features/repo-template.js
@@ -29,13 +29,13 @@ export function initRepoTemplateSearch() {
             const filteredResponse = {success: true, results: []};
             filteredResponse.results.push({
               name: '',
-              value: ''
+              value: '',
             });
             // Parse the response from the api to work with our dropdown
             $.each(response.data, (_r, repo) => {
               filteredResponse.results.push({
                 name: htmlEscape(repo.repository.full_name),
-                value: repo.repository.id
+                value: repo.repository.id,
               });
             });
             return filteredResponse;
@@ -43,7 +43,7 @@ export function initRepoTemplateSearch() {
           cache: false,
         },
 
-        fullTextSearch: true
+        fullTextSearch: true,
       });
   };
   $('#uid').on('change', changeOwner);
diff --git a/web_src/js/features/repo-wiki.js b/web_src/js/features/repo-wiki.js
index d51bf35c8..03a2c68c5 100644
--- a/web_src/js/features/repo-wiki.js
+++ b/web_src/js/features/repo-wiki.js
@@ -60,7 +60,7 @@ async function initRepoWikiFormEditor() {
         'gitea-code-inline', 'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|',
         'unordered-list', 'ordered-list', '|',
         'link', 'image', 'table', 'horizontal-rule', '|',
-        'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea'
+        'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea',
       ],
     },
   });
diff --git a/web_src/js/features/tribute.js b/web_src/js/features/tribute.js
index 055777be7..70a5de691 100644
--- a/web_src/js/features/tribute.js
+++ b/web_src/js/features/tribute.js
@@ -25,7 +25,7 @@ function makeCollections({mentions, emoji}) {
       },
       menuItemTemplate: (item) => {
         return `<div class="tribute-item">${emojiHTML(item.original)}<span>${htmlEscape(item.original)}</span></div>`;
-      }
+      },
     });
   }
 
@@ -41,7 +41,7 @@ function makeCollections({mentions, emoji}) {
             ${item.original.fullname && item.original.fullname !== '' ? `<span class="fullname">${htmlEscape(item.original.fullname)}</span>` : ''}
           </div>
         `;
-      }
+      },
     });
   }
 
diff --git a/web_src/js/features/user-auth-webauthn.js b/web_src/js/features/user-auth-webauthn.js
index 363e03976..6dfbb4d76 100644
--- a/web_src/js/features/user-auth-webauthn.js
+++ b/web_src/js/features/user-auth-webauthn.js
@@ -26,7 +26,7 @@ export async function initUserAuthWebAuthn() {
   }
   try {
     const credential = await navigator.credentials.get({
-      publicKey: options.publicKey
+      publicKey: options.publicKey,
     });
     await verifyAssertion(credential);
   } catch (err) {
@@ -37,7 +37,7 @@ export async function initUserAuthWebAuthn() {
     delete options.publicKey.extensions.appid;
     try {
       const credential = await navigator.credentials.get({
-        publicKey: options.publicKey
+        publicKey: options.publicKey,
       });
       await verifyAssertion(credential);
     } catch (err) {
@@ -185,7 +185,7 @@ async function webAuthnRegisterRequest() {
 
   try {
     const credential = await navigator.credentials.create({
-      publicKey: options.publicKey
+      publicKey: options.publicKey,
     });
     await webauthnRegistered(credential);
   } catch (err) {
diff --git a/web_src/js/markup/anchors.js b/web_src/js/markup/anchors.js
index 6cf83eb42..0e2c92713 100644
--- a/web_src/js/markup/anchors.js
+++ b/web_src/js/markup/anchors.js
@@ -1,50 +1,70 @@
 import {svg} from '../svg.js';
 
-const headingSelector = '.markup h1, .markup h2, .markup h3, .markup h4, .markup h5, .markup h6';
+const addPrefix = (str) => `user-content-${str}`;
+const removePrefix = (str) => str.replace(/^user-content-/, '');
+const hasPrefix = (str) => str.startsWith('user-content-');
 
 // scroll to anchor while respecting the `user-content` prefix that exists on the target
-function scrollToAnchor(hash, initial) {
-  // abort if the browser has already scrolled to another anchor during page load
-  if (initial && document.querySelector(':target')) return;
-  if (hash?.length <= 1) return;
-  const id = decodeURIComponent(hash.substring(1));
-  const el = document.getElementById(`user-content-${id}`);
-  if (el) {
-    el.scrollIntoView();
-  } else if (id.startsWith('user-content-')) { // compat for links with old 'user-content-' prefixed hashes
-    const el = document.getElementById(id);
-    if (el) el.scrollIntoView();
+function scrollToAnchor(encodedId) {
+  if (!encodedId) return;
+  const id = decodeURIComponent(encodedId);
+  const prefixedId = addPrefix(id);
+  let el = document.getElementById(prefixedId);
+
+  // check for matching user-generated `a[name]`
+  if (!el) {
+    const nameAnchors = document.getElementsByName(prefixedId);
+    if (nameAnchors.length) {
+      el = nameAnchors[0];
+    }
   }
+
+  // compat for links with old 'user-content-' prefixed hashes
+  if (!el && hasPrefix(id)) {
+    return document.getElementById(id)?.scrollIntoView();
+  }
+
+  el?.scrollIntoView();
 }
 
 export function initMarkupAnchors() {
-  if (!document.querySelector('.markup')) return;
+  const markupEls = document.querySelectorAll('.markup');
+  if (!markupEls.length) return;
 
-  // create link icons for markup headings, the resulting link href will remove `user-content-`
-  for (const heading of document.querySelectorAll(headingSelector)) {
-    const originalId = heading.id.replace(/^user-content-/, '');
-    const a = document.createElement('a');
-    a.classList.add('anchor');
-    a.setAttribute('href', `#${encodeURIComponent(originalId)}`);
-    a.innerHTML = svg('octicon-link');
-    a.addEventListener('click', (e) => {
-      scrollToAnchor(e.currentTarget.getAttribute('href'), false);
-    });
-    heading.prepend(a);
-  }
+  for (const markupEl of markupEls) {
+    // create link icons for markup headings, the resulting link href will remove `user-content-`
+    for (const heading of markupEl.querySelectorAll('h1, h2, h3, h4, h5, h6')) {
+      const a = document.createElement('a');
+      a.classList.add('anchor');
+      a.setAttribute('href', `#${encodeURIComponent(removePrefix(heading.id))}`);
+      a.innerHTML = svg('octicon-link');
+      heading.prepend(a);
+    }
 
-  // handle user-defined `name` anchors like `[Link](#link)` linking to `<a name="link"></a>Link`
-  for (const a of document.querySelectorAll('.markup a[href^="#"]')) {
-    const href = a.getAttribute('href');
-    if (!href.startsWith('#user-content-')) continue;
-    const originalId = href.replace(/^#user-content-/, '');
-    a.setAttribute('href', `#${encodeURIComponent(originalId)}`);
-    if (a.closest('.markup').querySelectorAll(`a[name="${originalId}"]`).length !== 1) {
+    // remove `user-content-` prefix from links so they don't show in url bar when clicked
+    for (const a of markupEl.querySelectorAll('a[href^="#"]')) {
+      const href = a.getAttribute('href');
+      if (!href.startsWith('#user-content-')) continue;
+      a.setAttribute('href', `#${removePrefix(href.substring(1))}`);
+    }
+
+    // add `user-content-` prefix to user-generated `a[name]` link targets
+    // TODO: this prefix should be added in backend instead
+    for (const a of markupEl.querySelectorAll('a[name]')) {
+      const name = a.getAttribute('name');
+      if (!name) continue;
+      a.setAttribute('name', addPrefix(a.name));
+    }
+
+    for (const a of markupEl.querySelectorAll('a[href^="#"]')) {
       a.addEventListener('click', (e) => {
-        scrollToAnchor(e.currentTarget.getAttribute('href'), false);
+        scrollToAnchor(e.currentTarget.getAttribute('href')?.substring(1));
       });
     }
   }
 
-  scrollToAnchor(window.location.hash, true);
+  // scroll to anchor unless the browser has already scrolled somewhere during page load
+  if (!document.querySelector(':target')) {
+    scrollToAnchor(window.location.hash?.substring(1));
+  }
 }
diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js
index e7eb39f45..220c9e551 100644
--- a/web_src/js/modules/tippy.js
+++ b/web_src/js/modules/tippy.js
@@ -148,7 +148,7 @@ export function initGlobalTooltips() {
   const observerConnect = (observer) => observer.observe(document, {
     subtree: true,
     childList: true,
-    attributeFilter: ['data-tooltip-content', 'title']
+    attributeFilter: ['data-tooltip-content', 'title'],
   });
   const observer = new MutationObserver((mutationList, observer) => {
     const pending = observer.takeRecords();
diff --git a/web_src/js/standalone/forgejo-swagger.js b/web_src/js/standalone/forgejo-swagger.js
index 2419bdb3c..896a1364c 100644
--- a/web_src/js/standalone/forgejo-swagger.js
+++ b/web_src/js/standalone/forgejo-swagger.js
@@ -11,11 +11,11 @@ window.addEventListener('load', async () => {
     docExpansion: 'none',
     defaultModelRendering: 'model', // don't show examples by default, because they may be incomplete
     presets: [
-      SwaggerUI.presets.apis
+      SwaggerUI.presets.apis,
     ],
     plugins: [
-      SwaggerUI.plugins.DownloadUrl
-    ]
+      SwaggerUI.plugins.DownloadUrl,
+    ],
   });
 
   window.ui = ui;
diff --git a/web_src/js/standalone/swagger.js b/web_src/js/standalone/swagger.js
index cb91089da..00854ef5d 100644
--- a/web_src/js/standalone/swagger.js
+++ b/web_src/js/standalone/swagger.js
@@ -21,11 +21,11 @@ window.addEventListener('load', async () => {
     docExpansion: 'none',
     defaultModelRendering: 'model', // don't show examples by default, because they may be incomplete
     presets: [
-      SwaggerUI.presets.apis
+      SwaggerUI.presets.apis,
     ],
     plugins: [
-      SwaggerUI.plugins.DownloadUrl
-    ]
+      SwaggerUI.plugins.DownloadUrl,
+    ],
   });
 
   window.ui = ui;
diff --git a/web_src/js/svg.js b/web_src/js/svg.js
index 471b5136b..3544b47c3 100644
--- a/web_src/js/svg.js
+++ b/web_src/js/svg.js
@@ -189,7 +189,7 @@ export const SvgIcon = {
     name: {type: String, required: true},
     size: {type: Number, default: 16},
     className: {type: String, default: ''},
-    symbolId: {type: String}
+    symbolId: {type: String},
   },
   render() {
     let {svgOuter, svgInnerHtml} = svgParseOuterInner(this.name);
@@ -205,7 +205,7 @@ export const SvgIcon = {
 
     // make the <SvgIcon class="foo" class-name="bar"> classes work together
     const classes = [];
-    for (const cls of svgOuter.classList) {
+    for (const cls of svgOuter.classList.values()) {
       classes.push(cls);
     }
     // TODO: drop the `className/class-name` prop in the future, only use "class" prop
diff --git a/web_src/js/utils/dom.js b/web_src/js/utils/dom.js
index 016c3b55f..703f15d41 100644
--- a/web_src/js/utils/dom.js
+++ b/web_src/js/utils/dom.js
@@ -191,7 +191,7 @@ export function autosize(textarea, {viewportMarginBottom = 0} = {}) {
       textarea.removeEventListener('mousemove', onUserResize);
       textarea.removeEventListener('input', resizeToFit);
       textarea.form?.removeEventListener('reset', onFormReset);
-    }
+    },
   };
 }
 
diff --git a/web_src/js/webcomponents/polyfills.js b/web_src/js/webcomponents/polyfills.js
index 88c727688..38f50fa02 100644
--- a/web_src/js/webcomponents/polyfills.js
+++ b/web_src/js/webcomponents/polyfills.js
@@ -9,7 +9,7 @@ try {
       return {
         format(value) {
           return ` ${value} ${options.unit}`;
-        }
+        },
       };
     }
     return intlNumberFormat(locales, options);
diff --git a/webpack.config.js b/webpack.config.js
index 0a0f573a3..8ab96b08a 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -182,7 +182,7 @@ export default {
                 ],
               },
             },
-          }
+          },
         ],
       },
       {
@@ -195,14 +195,14 @@ export default {
         type: 'asset/resource',
         generator: {
           filename: 'fonts/[name].[contenthash:8][ext]',
-        }
+        },
       },
       {
         test: /\.png$/i,
         type: 'asset/resource',
         generator: {
           filename: 'img/webpack/[name].[contenthash:8][ext]',
-        }
+        },
       },
     ],
   },