diff --git a/components/account/AccountHandle.vue b/components/account/AccountHandle.vue
index 2f3b1981..8173d99c 100644
--- a/components/account/AccountHandle.vue
+++ b/components/account/AccountHandle.vue
@@ -10,7 +10,7 @@ const serverName = $computed(() => getServerName(account))
 
 <template>
   <p>
-    <span>{{ getShortHandle(account) }}</span>
-    <span v-if="serverName" text="gray/95">@{{ serverName }}</span>
+    <span text-secondary>{{ getShortHandle(account) }}</span>
+    <span v-if="serverName" text-secondary-light>@{{ serverName }}</span>
   </p>
 </template>
diff --git a/components/account/AccountHeader.vue b/components/account/AccountHeader.vue
index 9d486fd6..2a3ed393 100644
--- a/components/account/AccountHeader.vue
+++ b/components/account/AccountHeader.vue
@@ -67,7 +67,7 @@ function previewAvatar() {
           </button>
           <div flex flex-col>
             <ContentRich font-bold text-2xl break-words :content="getDisplayName(account, { rich: true })" :emojis="account.emojis" />
-            <AccountHandle :account="account" op50 />
+            <AccountHandle :account="account" />
           </div>
         </div>
         <div flex gap-2 items-center>
@@ -81,12 +81,12 @@ function previewAvatar() {
         </div>
       </div>
       <div v-if="account.note">
-        <ContentRich text-4 text-gray :content="account.note" :emojis="account.emojis" />
+        <ContentRich text-4 text-secondary :content="account.note" :emojis="account.emojis" />
       </div>
       <div flex flex-wrap gap-4>
-        <div v-for="field in fields" :key="field.name" flex="~ gap-1" items-center>
-          <div v-if="getFieldNameIcon(field.name)" op50 :class="getFieldNameIcon(field.name)" :title="field.name" />
-          <div v-else op50 uppercase text-xs font-bold>
+        <div v-for="field in fields" :key="field.name" flex="~ gap-1" items-center >
+          <div v-if="getFieldNameIcon(field.name)" text-secondary :class="getFieldNameIcon(field.name)" :title="field.name" />
+          <div v-else text-secondary uppercase text-xs font-bold>
             {{ field.name }} |
           </div>
           <ContentRich text-sm filter-saturate-0 :content="field.value" />
@@ -94,13 +94,13 @@ function previewAvatar() {
       </div>
       <div flex gap-5>
         <NuxtLink :to="getAccountPath(account)" exact-active-class="text-primary">
-          <span font-bold>{{ formattedNumber(account.statusesCount) }}</span> <span op50>Posts</span>
+          <span font-bold>{{ formattedNumber(account.statusesCount) }}</span> <span text-secondary>Posts</span>
         </NuxtLink>
         <NuxtLink :to="`${getAccountPath(account)}/following`" exact-active-class="text-primary">
-          <span font-bold>{{ humanReadableNumber(account.followingCount) }}</span> <span op50>Following</span>
+          <span font-bold>{{ humanReadableNumber(account.followingCount) }}</span> <span text-secondary>Following</span>
         </NuxtLink>
         <NuxtLink :to="`${getAccountPath(account)}/followers`" exact-active-class="text-primary">
-          <span font-bold>{{ humanReadableNumber(account.followersCount) }}</span> <span op50>Followers</span>
+          <span font-bold>{{ humanReadableNumber(account.followersCount) }}</span> <span text-secondary>Followers</span>
         </NuxtLink>
       </div>
     </div>
diff --git a/components/account/AccountHoverCard.vue b/components/account/AccountHoverCard.vue
index 149d13a6..ab373ccb 100644
--- a/components/account/AccountHoverCard.vue
+++ b/components/account/AccountHoverCard.vue
@@ -9,7 +9,7 @@ defineProps<{
 <template>
   <div bg-base border="~ base" rounded w-80 z-900 overflow-hidden p-4 class="account-hover-card">
     <AccountInfo :account="account" />
-    <div text-sm flex flex-row text-gray mt-4>
+    <div text-sm flex flex-row text-secondary mt-4>
       <NuxtLink :to="`/${getFullHandle(account)}/`">
         {{ formattedNumber(account.statusesCount) }} Posts
       </NuxtLink>
@@ -22,6 +22,6 @@ defineProps<{
         {{ humanReadableNumber(account.followersCount) }} Followers
       </NuxtLink>
     </div>
-    <ContentRich text-4 text-gray :content="account.note" :emojis="account.emojis" />
+    <ContentRich text-4 text-secondary :content="account.note" :emojis="account.emojis" />
   </div>
 </template>
diff --git a/components/account/AccountInfo.vue b/components/account/AccountInfo.vue
index ff0167b7..13f4d148 100644
--- a/components/account/AccountInfo.vue
+++ b/components/account/AccountInfo.vue
@@ -18,7 +18,7 @@ const { account, link = true, fullServer = false } = defineProps<{
     </div>
     <NuxtLink flex flex-col :to="link ? getAccountPath(account) : null">
       <ContentRich font-bold hover:underline :content="getDisplayName(account, { rich: true })" :emojis="account.emojis" />
-      <AccountHandle :account="account" text-sm op35 />
+      <AccountHandle :account="account" text-sm />
       <slot name="bottom" />
     </NuxtLink>
     <slot />
diff --git a/components/common/CommonPaginator.vue b/components/common/CommonPaginator.vue
index c6fcf594..fbe286c6 100644
--- a/components/common/CommonPaginator.vue
+++ b/components/common/CommonPaginator.vue
@@ -28,13 +28,13 @@ const { items, state, endAnchor, error } = usePaginator(paginator)
     </template>
     <div ref="endAnchor" />
     <div v-if="state === 'loading'" p5 text-center flex="~ col" items-center animate-pulse>
-      <div op50 i-ri:loader-2-fill animate-spin text-2xl />
-      <span op50>Loading...</span>
+      <div text-secondary i-ri:loader-2-fill animate-spin text-2xl />
+      <span text-secondary>Loading...</span>
     </div>
-    <div v-else-if="state === 'done'" p5 op50 italic text-center>
+    <div v-else-if="state === 'done'" p5 text-secondary italic text-center>
       End of the list
     </div>
-    <div v-else-if="state === 'error'" p5 op50>
+    <div v-else-if="state === 'error'" p5 text-secondary>
       ERROR: {{ error }}
     </div>
   </div>
diff --git a/components/common/dropdown/DropdownItem.vue b/components/common/dropdown/DropdownItem.vue
index 6fcd81c2..4c967302 100644
--- a/components/common/dropdown/DropdownItem.vue
+++ b/components/common/dropdown/DropdownItem.vue
@@ -27,7 +27,7 @@ const handleClick = (evt: MouseEvent) => {
       <div text-15px>
         <slot />
       </div>
-      <div text-3 text="gray/90">
+      <div text-3 text-secondary>
         <slot name="description">
           <p v-if="description">
             {{ description }}
diff --git a/components/nav/NavFooter.vue b/components/nav/NavFooter.vue
index 61a610a4..cecee0fc 100644
--- a/components/nav/NavFooter.vue
+++ b/components/nav/NavFooter.vue
@@ -6,7 +6,7 @@ const buildTimeAgo = useTimeAgo(buildTime)
 </script>
 
 <template>
-  <div p4 text-sm op25 flex="~ col">
+  <div p4 text-sm text-secondary-light flex="~ col">
     <div flex="~ gap2">
       <button i-ri-sun-line dark:i-ri-moon-line text-lg mb4 @click="toggleDark()" />
       <button
diff --git a/components/nav/NavTitle.vue b/components/nav/NavTitle.vue
index 3897f2ab..d5461c1b 100644
--- a/components/nav/NavTitle.vue
+++ b/components/nav/NavTitle.vue
@@ -3,7 +3,7 @@
   <NuxtLink flex px3 py2 items-center text-2xl gap-2 hover:bg-active focus-visible:ring="2 current" rounded-full to="/" external>
     <img aria-label="Elk Logo" src="/logo.svg" w-10 h-10>
     <div>
-      Elk <sup text-sm italic op50 mt-1>alpha</sup>
+      Elk <sup text-sm italic text-secondary mt-1>alpha</sup>
     </div>
   </NuxtLink>
 </template>
diff --git a/components/publish/PublishWidget.vue b/components/publish/PublishWidget.vue
index 5d140f7a..5229cdd9 100644
--- a/components/publish/PublishWidget.vue
+++ b/components/publish/PublishWidget.vue
@@ -150,7 +150,7 @@ onUnmounted(() => {
   <div v-if="currentUser" flex="~ col gap-1">
     <template v-if="draft.editingStatus">
       <div flex="~ col gap-1">
-        <div text-gray self-center>
+        <div text-secondary self-center>
           Editing
         </div>
         <StatusCard :status="draft.editingStatus" :actions="false" :hover="false" />
@@ -235,7 +235,7 @@ onUnmounted(() => {
           <CommonDropdown>
             <button btn-action-icon w-12>
               <div :class="currentVisibility.icon" />
-              <div i-ri:arrow-down-s-line text-sm op50 mr--1 />
+              <div i-ri:arrow-down-s-line text-sm text-secondary mr--1 />
             </button>
 
             <template #popper>
diff --git a/components/status/StatusAccountDetails.vue b/components/status/StatusAccountDetails.vue
index eed00a3a..f8751db8 100644
--- a/components/status/StatusAccountDetails.vue
+++ b/components/status/StatusAccountDetails.vue
@@ -13,6 +13,6 @@ const { account, link = true } = defineProps<{
     flex="~ col" min-w-0 md:flex="~ row gap-2" md:items-center
   >
     <ContentRich font-bold break-words hover:underline :content="getDisplayName(account, { rich: true })" :emojis="account.emojis" />
-    <AccountHandle :account="account" op50 />
+    <AccountHandle :account="account" />
   </NuxtLink>
 </template>
diff --git a/components/status/StatusCard.vue b/components/status/StatusCard.vue
index 8d6c220a..2aa1b1a7 100644
--- a/components/status/StatusCard.vue
+++ b/components/status/StatusCard.vue
@@ -40,7 +40,7 @@ const timeago = useTimeAgo(() => status.createdAt, timeAgoOptions)
 <template>
   <div :id="`status-${status.id}`" ref="el" flex flex-col gap-2 px-4 transition-100 :class="{ 'hover:bg-active': hover }" tabindex="0" focus:outline-none focus-visible:ring="2 primary" @click="onclick" @keydown.enter="onclick">
     <div v-if="rebloggedBy" pl8>
-      <div flex="~ wrap" gap-1 items-center text-gray:75 text-sm>
+      <div flex="~ wrap" gap-1 items-center text-secondary text-sm>
         <div i-ri:repeat-fill mr-1 />
         <AccountInlineInfo font-bold :account="rebloggedBy" />
         reblogged
@@ -52,10 +52,10 @@ const timeago = useTimeAgo(() => status.createdAt, timeAgoOptions)
         <div flex>
           <StatusAccountDetails :account="status.account" />
           <div flex-auto />
-          <div text-sm op50 flex="~ row nowrap" hover:underline>
+          <div text-sm text-secondary flex="~ row nowrap" hover:underline>
             <CommonTooltip :content="createdAt">
               <a :title="status.createdAt" :href="getStatusPath(status)" @click.prevent="go">
-                <time text-sm op50 hover:underline :datetime="status.createdAt">
+                <time text-sm hover:underline :datetime="status.createdAt">
                   {{ timeago }}
                 </time>
               </a>
diff --git a/components/status/StatusDetails.vue b/components/status/StatusDetails.vue
index 4547adcf..4dfd326a 100644
--- a/components/status/StatusDetails.vue
+++ b/components/status/StatusDetails.vue
@@ -30,7 +30,7 @@ const visibility = $computed(() => STATUS_VISIBILITIES.find(v => v.value === sta
         :status="status"
       />
     </StatusSpoiler>
-    <div flex="~ gap-1" items-center op50 text-sm>
+    <div flex="~ gap-1" items-center text-secondary text-sm>
       <div flex>
         <div>{{ createdAt }}</div>
         <StatusEditIndicator
diff --git a/components/status/StatusReplyingTo.vue b/components/status/StatusReplyingTo.vue
index 66ae05c2..07047a34 100644
--- a/components/status/StatusReplyingTo.vue
+++ b/components/status/StatusReplyingTo.vue
@@ -11,11 +11,11 @@ const account = asyncComputed(() => fetchAccount(status.inReplyToAccountId!))
 <template>
   <NuxtLink
     v-if="status.inReplyToId"
-    flex="~ wrap" items-center text-sm text-gray:85
+    flex="~ wrap" items-center text-sm text-secondary
     :to="getStatusInReplyToPath(status)"
     :title="account ? `Replying to ${getDisplayName(account)}` : 'Replying to someone'"
   >
-    <div i-ri:reply-fill rotate-180 op50 class="mr-1.5" />
+    <div i-ri:reply-fill rotate-180 text-secondary class="mr-1.5" />
     <AccountInlineInfo v-if="account" :account="account" :link="false" />
     <span v-else>Someone</span>
     's post
diff --git a/components/status/edit/StatusEditIndicator.vue b/components/status/edit/StatusEditIndicator.vue
index dde3e5eb..6c8f0bd4 100644
--- a/components/status/edit/StatusEditIndicator.vue
+++ b/components/status/edit/StatusEditIndicator.vue
@@ -17,6 +17,7 @@ const formatted = useFormattedDateTime(status.editedAt)
         :title="editedAt"
         :datetime="editedAt"
         font-bold underline decoration-dashed
+        text-secondary
       >&nbsp;*</time>
     </CommonTooltip>
 
diff --git a/components/tiptap/TiptapMentionList.vue b/components/tiptap/TiptapMentionList.vue
index f1264a14..51dd2e1f 100644
--- a/components/tiptap/TiptapMentionList.vue
+++ b/components/tiptap/TiptapMentionList.vue
@@ -46,7 +46,7 @@ defineExpose({
       <button
         v-for="(item, index) in items"
         :key="index"
-        :class="index === selectedIndex ? 'bg-active' : 'op50'"
+        :class="index === selectedIndex ? 'bg-active' : 'text-secondary'"
         block m0 w-full text-left px2 py1
         @click="selectItem(index)"
       >
diff --git a/components/user/UserSignIn.vue b/components/user/UserSignIn.vue
index 7006e91b..b6ff1e6a 100644
--- a/components/user/UserSignIn.vue
+++ b/components/user/UserSignIn.vue
@@ -24,7 +24,7 @@ async function handleInput() {
     </div>
     <div>Mastodon Server Name</div>
     <div flex bg-gray:10 px2 py1 mxa rounded border="~ border" text-xl items-center>
-      <span op35 mr1 text-sm>https://</span>
+      <span text-secondary-light mr1 text-sm>https://</span>
       <input v-model="server" :placeholder="DEFAULT_SERVER" outline-none bg-transparent @input="handleInput">
     </div>
     <button btn-solid mt2>
diff --git a/components/user/UserSignInEntry.vue b/components/user/UserSignInEntry.vue
index 495f0576..62b46cbc 100644
--- a/components/user/UserSignInEntry.vue
+++ b/components/user/UserSignInEntry.vue
@@ -1,6 +1,6 @@
 <template>
   <div p8 flex="~ col gap4">
-    <div text-sm op50>
+    <div text-sm text-secondary>
       Sign in to follow profiles or hashtags, favourite, share and reply to posts, or interact from your account on a different server.
     </div>
     <button class="btn-solid text-center" @click="openSigninDialog()">
diff --git a/styles/vars.css b/styles/vars.css
index 5a33582a..8de2c2e8 100644
--- a/styles/vars.css
+++ b/styles/vars.css
@@ -8,6 +8,7 @@
   --c-bg-selection: #8885;
   --c-text-base: #222;
   --c-text-secondary: #888;
+  --c-text-secondary-light: #bbb;
 }
 
 .dark {
@@ -15,4 +16,5 @@
   --c-bg-active: #151515;
   --c-bg-code: #ffffff06;
   --c-text-base: #fff;
+  --c-text-secondary-light: #555;
 }
diff --git a/unocss.config.ts b/unocss.config.ts
index feb551c1..f34c8c56 100644
--- a/unocss.config.ts
+++ b/unocss.config.ts
@@ -22,6 +22,7 @@ export default defineConfig({
       // text
       'text-base': 'text-$c-text-base',
       'text-secondary': 'text-$c-text-secondary',
+      'text-secondary-light': 'text-$c-text-secondary-light',
 
       // buttons
       'btn-base': 'cursor-pointer disabled:opacity-50 disabled:pointer-events-none disabled:saturate-0 disabled:brightness-[0.7] disabled:contrast-[2]',