diff --git a/.editorconfig b/.editorconfig
index 2322ac0d2..7f32cfe8a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -3,5 +3,5 @@ root = true
[*.scss]
indent_size = 2
-[{**/login.scss,**/tangerine/**/*.scss,**/gts/**/*.scss}]
+[{**/login.scss,**/tangerine/**/*.scss,**/gts/**/*.scss,app/css/**/*.css}]
indent_size = 4
\ No newline at end of file
diff --git a/app/css/core/Manrope[wght].woff2 b/app/css/core/Manrope[wght].woff2
new file mode 100644
index 000000000..4d677aac3
Binary files /dev/null and b/app/css/core/Manrope[wght].woff2 differ
diff --git a/app/css/core/_core.css b/app/css/core/_core.css
index 0314fa8f8..f95c2d0d3 100644
--- a/app/css/core/_core.css
+++ b/app/css/core/_core.css
@@ -1,3 +1,101 @@
-body {
- border: 20px solid pink;
+@import "colors";
+@import "columns";
+@import "scrollbars";
+@import "sizes";
+
+@import "multiple-columns";
+
+@import "components/drawer";
+@import "components/search";
+@import "components/column";
+@import "components/notification-filter-bar";
+@import "components/status/status";
+
+@import "modules/feed";
+@import "modules/status";
+
+@font-face {
+ font-family: "Manrope";
+ src: url("Manrope[wght].woff2") format("woff2-variations");
+}
+
+* {
+ box-sizing: border-box;
+
+ &::before,
+ &::after {
+ box-sizing: inherit;
+ }
+}
+
+body {
+ margin: 0;
+ font-family: "Manrope", ui-rounded, sans-serif;
+ color: var(--color-fg);
+ line-height: 1.5;
+ text-rendering: optimizelegibility;
+ background: var(--color-bg);
+}
+
+.ui {
+ width: 100%;
+ height: 100%;
+}
+
+button {
+ display: block;
+ padding: 6px;
+ border: 1px solid transparent;
+ color: var(--color-content-fg);
+ font: inherit;
+ line-height: inherit;
+ border-radius: 6px;
+ background-color: var(--color-content-secondary-bg);
+
+ &:is(:active, :focus, :hover) {
+ color: var(--color-accent);
+ background-color: var(--color-accent-bg);
+ }
+
+ &:focus-visible {
+ outline: solid 2px var(--color-accent-focus);
+ outline-offset: 2px;
+ }
+}
+
+button:has(svg) {
+ display: flex;
+ align-items: center;
+}
+
+img {
+ max-width: 100px;
+}
+
+svg.gts-icon {
+ display: block;
+ width: var(--size-icon);
+ height: var(--size-icon);
+}
+
+.compose-form__buttons {
+ display: flex;
+ gap: 5px;
+}
+
+.emojione {
+ --size: min(1em, 20px);
+
+ width: var(--size);
+ height: var(--size);
+}
+
+.ui__header,
+.search__popout,
+.drawer__inner__mastodon {
+ display: none;
+}
+
+.upload-area {
+ position: fixed;
}
diff --git a/app/css/core/colors.css b/app/css/core/colors.css
new file mode 100644
index 000000000..66b77f917
--- /dev/null
+++ b/app/css/core/colors.css
@@ -0,0 +1,39 @@
+/* 🎨 Colors */
+:root {
+ color-scheme: light dark;
+
+ --color-bg: #f2eff5;
+ --gradient-bg: linear-gradient(90deg, var(--color-bg), var(--color-bg));
+ --color-fg: #2a2d37;
+ --color-fg-muted: #888494;
+ --color-secondary-bg: #e8e4f2;
+ --color-secondary-separator: #dfdbed;
+
+ --color-content-bg: #ffffff;
+ --color-content-fg: #444a5a;
+ --color-content-fg-bold: #000000;
+ --color-content-fg-muted: color-mix(
+ in srgb,
+ var(--color-content-fg),
+ var(--color-content-bg) 40%
+ );
+ --color-content-secondary-bg: #f5f4f9;
+ --color-content-secondary-separator: rgba(223, 219, 237, 0.4);
+ --color-content-bg-focus: #fffcfa;
+
+ --color-accent: #5758ff;
+ --color-accent-focus: #563acc;
+ --color-accent-lines: rgba(99, 100, 255, 0.12);
+ --color-accent-bg: #e5ddf6;
+ --color-accent-fg: #ffffff;
+
+ --color-lines: #e1dde4;
+ --color-lines-translucent: rgba(0, 0, 0, 0.15);
+
+ --color-confirm: #79bd9a;
+ --color-confirm-bg: rgba(121, 189, 154, 0.3);
+ --color-confirm-fg: #4e8a6b;
+
+ --color-reject: #df405a;
+ --color-reject-bg: rgba(223, 64, 90, 0.3);
+}
diff --git a/app/css/core/columns.css b/app/css/core/columns.css
new file mode 100644
index 000000000..f7f6bf839
--- /dev/null
+++ b/app/css/core/columns.css
@@ -0,0 +1,24 @@
+.columns-area {
+ display: flex;
+ padding: var(--size-layout-gap);
+ column-gap: var(--size-layout-gap);
+}
+
+.column {
+ display: flex;
+ flex-direction: column;
+ flex-shrink: 0;
+ overflow: hidden;
+ border: 1px solid var(--color-lines);
+ border-radius: var(--size-layout-radius);
+ background: var(--color-content-bg);
+
+ .layout-multiple-columns & {
+ width: 400px;
+ }
+}
+
+.column > .scrollable {
+ max-height: 100%;
+ overflow-y: scroll;
+}
diff --git a/app/css/core/components/column.css b/app/css/core/components/column.css
new file mode 100644
index 000000000..470370a29
--- /dev/null
+++ b/app/css/core/components/column.css
@@ -0,0 +1 @@
+@import "components/column/column-header";
diff --git a/app/css/core/components/column/column-header.css b/app/css/core/components/column/column-header.css
new file mode 100644
index 000000000..ce93a1a3e
--- /dev/null
+++ b/app/css/core/components/column/column-header.css
@@ -0,0 +1,32 @@
+.column-header {
+ display: flex;
+ margin: 0;
+ font-size: max(16px, 1rem);
+ font-weight: bold;
+ backdrop-filter: blur(20px);
+}
+
+.column-header > button {
+ display: flex;
+ align-items: center;
+ flex-grow: 1;
+ gap: 15px;
+ padding-inline-start: 15px;
+ color: var(--color-content-fg);
+ background: var(--color-content-bg);
+
+ &:hover {
+ color: inherit;
+ background-color: transparent;
+ }
+}
+
+.column-header__buttons {
+ display: flex;
+ gap: var(--size-ui-gap);
+ padding: 5px;
+
+ > button {
+ background-color: transparent;
+ }
+}
diff --git a/app/css/core/components/drawer.css b/app/css/core/components/drawer.css
new file mode 100644
index 000000000..534115235
--- /dev/null
+++ b/app/css/core/components/drawer.css
@@ -0,0 +1,33 @@
+.drawer {
+ display: flex;
+ flex-direction: column;
+ row-gap: var(--size-layout-gap);
+ min-width: 300px;
+ max-width: 400px;
+}
+
+.drawer__header {
+ display: flex;
+ column-gap: var(--size-ui-gap);
+ padding: 5px;
+ border: 1px solid var(--color-lines);
+ border-radius: var(--size-layout-radius);
+ background: var(--color-content-bg);
+}
+
+.drawer__header a {
+ --size-icon: 24px;
+
+ display: flex;
+ align-items: center;
+ flex-grow: 1;
+ justify-content: center;
+ padding: 8px;
+ border-radius: var(--size-ui-radius);
+ color: inherit;
+ transition: all 0.3s;
+
+ &:is(:active, :focus, :hover) {
+ background-color: var(--color-accent-bg);
+ }
+}
diff --git a/app/css/core/components/notification-filter-bar.css b/app/css/core/components/notification-filter-bar.css
new file mode 100644
index 000000000..ac57e55a6
--- /dev/null
+++ b/app/css/core/components/notification-filter-bar.css
@@ -0,0 +1,66 @@
+.notification__filter-bar {
+ display: flex;
+}
+
+.notification__filter-bar {
+ display: flex;
+ gap: 8px;
+ margin-inline: -1px;
+ padding: 6px;
+ border: 1px solid var(--color-accent-lines);
+ background: var(--color-accent-bg);
+
+ a,
+ button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-grow: 1;
+ padding: 8px 6px;
+ min-width: 32px;
+ border: 0;
+ border-radius: var(--size-ui-radius);
+ color: var(--color-content-fg);
+ line-height: 20px;
+ text-decoration: none;
+ background: transparent;
+ transition: all 0.3s;
+
+ &:focus-visible,
+ &:hover {
+ background: var(--color-accent-lines);
+ }
+ }
+
+ a.active,
+ button.active {
+ color: var(--color-content-fg);
+ background: var(--color-content-bg);
+
+ /* &:focus-visible,
+ &:hover {
+ background: var(--color-notifications-bg--hover);
+ } */
+ }
+
+ a:not(:first-child),
+ button:not(:first-child) {
+ position: relative;
+
+ &::before {
+ position: absolute;
+ top: 6px;
+ right: calc(100% + 3px);
+ width: 2px;
+ height: 24px;
+ background: var(--color-accent-lines);
+ content: "";
+ }
+ }
+
+ svg.gts-icon {
+ --size: 20px;
+
+ display: block;
+ }
+}
diff --git a/app/css/core/components/search.css b/app/css/core/components/search.css
new file mode 100644
index 000000000..848a9c6c5
--- /dev/null
+++ b/app/css/core/components/search.css
@@ -0,0 +1,50 @@
+/* 🔍 Search */
+.search {
+ position: relative;
+ display: flex;
+}
+
+.search > input {
+ display: block;
+ padding: 12px 40px;
+ width: 100%;
+ border: 1px solid var(--color-accent-lines);
+ border-radius: var(--size-layout-radius);
+ color: var(--color-content-fg);
+ font: inherit;
+ font-weight: 500;
+ line-height: 20px;
+ background: var(--color-accent-bg);
+ transition: 0.2s;
+ transition-property: border-color, background-color, outline;
+
+ &::placeholder {
+ font-weight: 500;
+ color: var(--color-accent);
+ }
+
+ &:focus::placeholder {
+ color: var(--color-content-fg);
+ opacity: 0.4;
+ }
+}
+
+.search > .gts-icon {
+ --size-icon: 20px;
+
+ position: absolute;
+ top: 13px;
+ left: 13px;
+}
+
+.search > button {
+ position: absolute;
+ top: 7px;
+ right: 7px;
+ padding: 6px;
+ background: transparent;
+
+ &:not(.active) {
+ display: none;
+ }
+}
diff --git a/app/css/core/components/status/_status.css b/app/css/core/components/status/_status.css
new file mode 100644
index 000000000..34b4a1cbf
--- /dev/null
+++ b/app/css/core/components/status/_status.css
@@ -0,0 +1,10 @@
+/* 🚥 Status */
+@import "components/status/account";
+@import "components/status/action-bar";
+@import "components/status/avatar";
+@import "components/status/container";
+@import "components/status/content";
+@import "components/status/display-name";
+@import "components/status/icons";
+@import "components/status/info";
+@import "components/status/prepend";
diff --git a/app/css/core/components/status/account.css b/app/css/core/components/status/account.css
new file mode 100644
index 000000000..05de83b63
--- /dev/null
+++ b/app/css/core/components/status/account.css
@@ -0,0 +1,8 @@
+/* 🚥 Status: Account */
+.status__info__account {
+ display: grid;
+ grid-template-columns: auto 1fr;
+ gap: 10px;
+ overflow: hidden;
+ text-overflow: clip;
+}
diff --git a/app/css/core/components/status/action-bar.css b/app/css/core/components/status/action-bar.css
new file mode 100644
index 000000000..f2afcae08
--- /dev/null
+++ b/app/css/core/components/status/action-bar.css
@@ -0,0 +1,16 @@
+/* 🚥 Status: Action bar */
+.status__action-bar {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+
+ button {
+ color: var(--color-accent);
+ background-color: transparent;
+ }
+}
+
+.status__relative-time {
+ margin-left: auto;
+ color: var(--color-content-fg);
+}
diff --git a/app/css/core/components/status/avatar.css b/app/css/core/components/status/avatar.css
new file mode 100644
index 000000000..97d71cc00
--- /dev/null
+++ b/app/css/core/components/status/avatar.css
@@ -0,0 +1,38 @@
+/* 🚥 Status: Avatar */
+.status__avatar {
+}
+
+.status {
+ .account__avatar {
+ border-radius: var(--size-ui-radius);
+ }
+
+ .account__avatar-overlay {
+ position: relative;
+ padding-block-end: 10px;
+ padding-inline-end: 10px;
+ }
+
+ .account__avatar-overlay-base,
+ .account__avatar-overlay-overlay {
+ display: block;
+ width: var(--size-avatar);
+ height: var(--size-avatar);
+ border-radius: var(--size-ui-radius);
+ background-position: center;
+ background-size: cover;
+ background-repeat: no-repeat;
+ }
+
+ .account__avatar-overlay-base {
+ --size-avatar: 36px;
+ }
+
+ .account__avatar-overlay-overlay {
+ --size-avatar: 24px;
+
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ }
+}
diff --git a/app/css/core/components/status/container.css b/app/css/core/components/status/container.css
new file mode 100644
index 000000000..5c6fc5ab9
--- /dev/null
+++ b/app/css/core/components/status/container.css
@@ -0,0 +1,13 @@
+.status {
+ --color-status-bg: var(--color-content-bg);
+
+ display: flex;
+ flex-direction: column;
+ row-gap: var(--size-layout-gap);
+ padding: 15px;
+ text-wrap: pretty;
+
+ a {
+ word-break: break-word;
+ }
+}
diff --git a/app/css/core/components/status/content.css b/app/css/core/components/status/content.css
new file mode 100644
index 000000000..810d1efd3
--- /dev/null
+++ b/app/css/core/components/status/content.css
@@ -0,0 +1,37 @@
+/* 🚥 Status: Content */
+.status__content__text {
+ > :first-child {
+ margin-block-start: 0;
+ }
+
+ > :last-child {
+ margin-block-end: 0;
+ }
+}
+
+.status__content__text a {
+ color: var(--color-accent);
+ text-decoration-line: underline;
+ text-decoration-color: var(--color-accent-bg);
+ text-decoration-thickness: 2px;
+ text-underline-offset: 2px;
+
+ &:hover {
+ text-decoration-color: var(--color-accent);
+ }
+}
+
+.status__content__text a.mention {
+ text-decoration: none;
+
+ span {
+ text-decoration-line: underline;
+ text-decoration-color: var(--color-accent-bg);
+ text-decoration-thickness: 2px;
+ text-underline-offset: 2px;
+ }
+
+ &:is(:active, :focus, :hover) span {
+ text-decoration-color: var(--color-accent);
+ }
+}
diff --git a/app/css/core/components/status/display-name.css b/app/css/core/components/status/display-name.css
new file mode 100644
index 000000000..879034655
--- /dev/null
+++ b/app/css/core/components/status/display-name.css
@@ -0,0 +1,35 @@
+/* 🚥 Status: Display name */
+.status__display-name {
+ align-self: start;
+ justify-self: start;
+ color: var(--color-content-fg);
+ font-size: 15px;
+ line-height: 1.2;
+ text-decoration: none;
+ overflow: hidden;
+
+ .display-name {
+ display: block;
+ max-width: 100%;
+ overflow: hidden;
+ font-weight: 700;
+ text-overflow: clip;
+ }
+
+ .display-name__html {
+ font-weight: 700;
+ }
+
+ .display-name__account {
+ color: var(--color-secondary-fg);
+ font-weight: 400;
+ word-break: normal;
+ }
+
+ &:hover .display-name__html {
+ text-decoration-line: underline;
+ text-decoration-color: currentColor;
+ text-decoration-thickness: 2px;
+ text-underline-offset: 2px;
+ }
+}
diff --git a/app/css/core/components/status/icons.css b/app/css/core/components/status/icons.css
new file mode 100644
index 000000000..e9a9b19a0
--- /dev/null
+++ b/app/css/core/components/status/icons.css
@@ -0,0 +1,46 @@
+/* 🚥 Status: Icons */
+.status__info__icons {
+ --size-icon: 18px;
+
+ position: relative;
+ display: flex;
+ gap: 5px;
+ align-items: start;
+ color: var(--color-content-fg);
+
+ .text-icon {
+ font-size: 12px;
+ line-height: 20px;
+ }
+
+ &::before {
+ position: absolute;
+ top: 0;
+ right: calc(100% + 5px);
+ width: 20px;
+ height: 100%;
+ content: "";
+ background: linear-gradient(90deg, transparent, var(--color-status-bg));
+ transition: all 0.2s;
+ }
+}
+
+.status__info__icons button.icon-button {
+ display: block;
+ margin: -3px;
+ padding: 2px;
+ color: inherit;
+ background-color: transparent;
+
+ svg.gts-icon {
+ transition: transform ease-in-out 0.2s;
+ }
+
+ &.active svg.gts-icon {
+ transform: rotate(-180deg);
+ }
+
+ &:hover {
+ color: var(--color-accent-hover);
+ }
+}
diff --git a/app/css/core/components/status/info.css b/app/css/core/components/status/info.css
new file mode 100644
index 000000000..52a13843e
--- /dev/null
+++ b/app/css/core/components/status/info.css
@@ -0,0 +1,10 @@
+/* 🚥 Status: Info */
+.status__info {
+ display: grid;
+ gap: 5px;
+ grid-template-columns: 1fr auto;
+
+ .notification__message {
+ grid-column: 1/-1;
+ }
+}
diff --git a/app/css/core/components/status/prepend.css b/app/css/core/components/status/prepend.css
new file mode 100644
index 000000000..894397260
--- /dev/null
+++ b/app/css/core/components/status/prepend.css
@@ -0,0 +1,43 @@
+/* 🚥 Status: Prepend */
+.status__prepend {
+ display: inline-flex;
+ align-items: center;
+ align-self: start;
+ gap: 5px;
+ padding: 5px 10px;
+ border: 1px solid var(--color-accent-lines);
+ border-radius: 50px;
+ color: var(--color-content-fg);
+ font-size: 13px;
+ font-weight: 500;
+ background-color: var(--color-content-secondary-bg);
+
+ &:focus-within {
+ outline: 2px solid var(--color-accent-focus);
+ outline-offset: 3px;
+ }
+}
+
+.status__prepend-icon {
+ --size: 18px;
+
+ display: block;
+ width: var(--size);
+ height: var(--size);
+}
+
+.status__prepend-display-name {
+ color: inherit;
+ text-decoration: underline;
+ text-decoration-color: var(--color-accent-muted-fg);
+
+ &:hover {
+ color: inherit;
+ text-decoration-thickness: 2px;
+ }
+
+ &:focus-visible {
+ color: var(--color-accent-focus);
+ outline-color: transparent;
+ }
+}
diff --git a/app/css/core/modules/feed.css b/app/css/core/modules/feed.css
new file mode 100644
index 000000000..591464f55
--- /dev/null
+++ b/app/css/core/modules/feed.css
@@ -0,0 +1,8 @@
+[role="feed"].item-list {
+}
+
+[role="feed"].item-list > article {
+ &:not(:last-child) {
+ border-bottom: 1px solid var(--color-lines);
+ }
+}
diff --git a/app/css/core/modules/status.css b/app/css/core/modules/status.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/app/css/core/multiple-columns.css b/app/css/core/multiple-columns.css
new file mode 100644
index 000000000..a5e05c89e
--- /dev/null
+++ b/app/css/core/multiple-columns.css
@@ -0,0 +1,17 @@
+body.layout-multiple-columns {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ padding-bottom: env(safe-area-inset-bottom);
+ padding-left: env(safe-area-inset-left);
+ padding-right: env(safe-area-inset-right);
+
+ :is(.app-holder, .app-holder > div, .columns-area) {
+ height: 100%;
+ }
+
+ .ui {
+ display: flex;
+ flex: 0 0 auto;
+ }
+}
diff --git a/app/css/core/scrollbars.css b/app/css/core/scrollbars.css
new file mode 100644
index 000000000..b6ebf1ae5
--- /dev/null
+++ b/app/css/core/scrollbars.css
@@ -0,0 +1,28 @@
+/* 🖱️ Scrollbars */
+:root:has(.app-body) *::-webkit-scrollbar-track {
+ background-color: var(--color-bg);
+ padding: 2px;
+}
+:root:has(.app-body) *::-webkit-scrollbar-thumb {
+ background-color: var(--color-accent);
+ border-radius: 8px;
+ opacity: 0.4;
+ box-shadow: none;
+}
+:root:has(.app-body) *::-webkit-scrollbar-track:hover {
+ background-color: var(--color-bg);
+}
+:root:has(.app-body) *::-webkit-scrollbar-thumb:hover {
+ background-color: var(--color-accent);
+ opacity: 0.7;
+}
+@media screen and (max-width: 1175px) {
+ :root:has(.app-body) *::-webkit-scrollbar {
+ display: none;
+ }
+}
+:root,
+* {
+ scrollbar-color: var(--color-accent) var(--color-bg);
+ scrollbar-width: thin;
+}
diff --git a/app/css/core/sizes.css b/app/css/core/sizes.css
new file mode 100644
index 000000000..a3d1b0f5d
--- /dev/null
+++ b/app/css/core/sizes.css
@@ -0,0 +1,9 @@
+/* 📏 Sizes */
+:root {
+ --size-layout-gap: 10px;
+ --size-layout-radius: 8px;
+ --size-ui-gap: 5px;
+ --size-ui-radius: 6px;
+
+ --size-icon: max(1em, 20px);
+}
diff --git a/public/index.html b/public/index.html
index d935cf7c8..2eb599214 100644
--- a/public/index.html
+++ b/public/index.html
@@ -19,10 +19,10 @@
-
+
-
+