<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Rolling in the Deep]]></title><description><![CDATA[Rolling in the Deep]]></description><link>https://hakujitsu.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 06 Oct 2026 06:19:00 GMT</lastBuildDate><atom:link href="https://hakujitsu.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[MmSecureVirtualMemoryEx를 활용한 메모리 보호]]></title><description><![CDATA[들어가며
이 글에선 MmSecureVirtualMemoryEx라는 API를 활용해 프로세스 메모리를 보호하는 방법에 대해 알아본다.
이 API는 문서화된 API치곤 정말 많이 안 알려진 편인데, 어느 정도로 안 알려져 있냐면...

이 API 이름으로 Github에 검색해 봤을 때 (헤더나 마크다운 등을 제외하고) 이 API를 사용하는 코드는 하나밖에 검색되지 않았다. (Easy Anti-Cheat와 같은 일부 보안 제품에서도 사용하고 있다는 ...]]></description><link>https://hakujitsu.hashnode.dev/protecting-memory-using-mmsecurevirtualmemoryex</link><guid isPermaLink="true">https://hakujitsu.hashnode.dev/protecting-memory-using-mmsecurevirtualmemoryex</guid><category><![CDATA[C++]]></category><category><![CDATA[Windows]]></category><category><![CDATA[Kernel]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Shin Jinhyeok]]></dc:creator><pubDate>Mon, 20 Nov 2023 15:34:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/lYxQ5F9xBDM/upload/b8d92891a81bd2ee4f19e3a17d6eb638.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-65ok7ja06rca66mw">들어가며</h1>
<p>이 글에선 <a target="_blank" href="https://learn.microsoft.com/ko-kr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-mmsecurevirtualmemoryex"><code>MmSecureVirtualMemoryEx</code></a>라는 API를 활용해 프로세스 메모리를 보호하는 방법에 대해 알아본다.</p>
<p>이 API는 문서화된 API치곤 정말 많이 안 알려진 편인데, 어느 정도로 안 알려져 있냐면...</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700493949240/fcf473cb-bb7f-4111-a5aa-9864674f82ba.png" alt class="image--center mx-auto" /></p>
<p>이 API 이름으로 Github에 검색해 봤을 때 <em>(헤더나 마크다운 등을 제외하고)</em> 이 API를 사용하는 코드는 하나밖에 검색되지 않았다. <em>(</em><a target="_blank" href="https://www.unknowncheats.me/forum/3110494-post3.html"><em>Easy Anti-Cheat와 같은 일부 보안 제품에서도 사용하고 있다는 듯하다.</em></a><em>)</em></p>
<p>이 글이 이 API를 쓰려고 했던 사람들이나, 이 API가 제공하는 기능이 필요했던 사람들에게 도움이 될 수 있었으면 좋겠다.</p>
<h1 id="heading-66mu66qo66asiouzto2yud8">메모리 보호?</h1>
<p>메모리 보호라는 게 무엇이고, 또 왜 필요할까?</p>
<p>이 글에서 이야기하는 '메모리 보호'란, <a target="_blank" href="https://learn.microsoft.com/ko-kr/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect"><code>VirtualProtect</code></a> 등 API를 사용해 페이지 보호 속성을 변경하는 것을 막는다는 의미이다.</p>
<ol>
<li><p>코드 영역에 쓰기 권한을 부여</p>
<ul>
<li><p>코드 변조</p>
<ul>
<li><p>주로 인라인 후킹에 사용</p>
</li>
<li><p>디버깅 시 소프트웨어 브레이크 포인트 삽입</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>읽기 전용 데이터 영역에 쓰기 권한을 부여</p>
<ul>
<li>IAT, EAT 후킹</li>
</ul>
</li>
</ol>
<p>주로 위와 같은 경우에 페이지 보호 속성을 변경하는 것이 필요한데, 이 API를 사용하면 이러한 행위들을 차단할 수 있다.</p>
<p>참고로 이 API는 기존 보호 속성보다 더 적은 권한을 가진 보호 속성으로의 변경도 차단한다.</p>
<p>즉, 이미 매핑된 영역을 강제로 언맵하는 것도 차단하기 때문에 프로세스 할로잉류의 공격들도 부분적으로 방어가 가능하다. <em>(참고로 이 기능은 하위 API인</em> <a target="_blank" href="https://learn.microsoft.com/ko-kr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-mmsecurevirtualmemory"><code>MmSecureVirtualMemory</code></a> API에서도 제공한다. <em>부분적이라 하는 이유는 일부 악성코드에서 프로세스 할로잉을 수행하지만 원래 이미지를 언맵하지 않는 경우가 있기 때문이다.</em>)</p>
<h1 id="heading-7iks7jqp67kv">사용법</h1>
<p>서론이 길었다. 본론으로 넘어가 API 사용법을 알아보도록 하자.</p>
<h2 id="heading-64ya7iobio2uhouhnoyeuoykpcdsvzjthy3siqttirjrozwg7kce7zmy">대상 프로세스 콘텍스트로 전환</h2>
<p>대상 프로세스의 가상 주소 공간을 사용하기 위해서이다.</p>
<p><em>(당연한 이야기지만)</em> 이미 대상 프로세스의 콘텍스트에서 실행되고 있는 상태라면 이 과정은 생략할 수 있다.</p>
<p>먼저 프로세스의 EPROCESS 구조체 주소를 알아내야 하는데, 내 경우에는 프로세스 아이디로 프로세스를 찾아야 했으므로 <a target="_blank" href="https://learn.microsoft.com/ko-kr/windows-hardware/drivers/ddi/ntifs/nf-ntifs-pslookupprocessbyprocessid"><code>PsLookupProcessByProcessId</code></a> API를 사용했다.</p>
<pre><code class="lang-cpp">xil::unique_process process;

NTSTATUS status = ::PsLookupProcessByProcessId(kTargetProcessId, &amp;process);

<span class="hljs-keyword">if</span> (!NT_SUCCESS(status))
{
    LOG(ERROR, <span class="hljs-string">"PsLookupProcessByProcessId failed. (%08X)"</span>, status);

    <span class="hljs-keyword">return</span> status;
}
</code></pre>
<p>그 다음 <a target="_blank" href="https://learn.microsoft.com/ko-kr/windows-hardware/drivers/ddi/ntifs/nf-ntifs-kestackattachprocess"><code>KeStackAttachProcess</code></a> API를 사용해서 해당 프로세스에 Attach 해 주면 된다.</p>
<pre><code class="lang-cpp">KAPC_STATE apc_state = {};

::KeStackAttachProcess(process.get(), &amp;apc_state);

<span class="hljs-keyword">auto</span> unstack_detach_process = wil::scope_exit(
    [&amp;]() INIT
    {
        ::KeUnstackDetachProcess(&amp;apc_state);
    });
</code></pre>
<p>메모리 보호 적용 후엔 잊지 않고 <a target="_blank" href="https://learn.microsoft.com/ko-kr/windows-hardware/drivers/ddi/ntifs/nf-ntifs-keunstackdetachprocess"><code>KeUnstackDetachProcess</code></a> API를 사용해 프로세스에서 Detach 해 줘야 한다.</p>
<h2 id="heading-66mu66qo66asiouzto2yucdsoihsmqk">메모리 보호 적용</h2>
<p><code>MM_SECURE_NO_CHANGE</code> 플래그와 함께 보호하려는 영역에 대해 <code>MmSecureVirtualMemoryEx</code> API를 호출한다.</p>
<pre><code class="lang-cpp">secure_handle = ::MmSecureVirtualMemoryEx(kAddress,
                                          kSize,
                                          PAGE_NOACCESS,
                                          MM_SECURE_NO_CHANGE);
</code></pre>
<p>API를 사용할 때 주의할 점이 몇 가지 있다.</p>
<ul>
<li><p>보호할 영역의 메모리는 유저 영역 메모리여야 한다.</p>
</li>
<li><p>모두 Commit 또는 Reserve 상태의 메모리여야 한다.</p>
</li>
<li><p><em>(</em><code>MM_SECURE_NO_CHANGE</code> 플래그 사용 시) 반드시 <code>ProbeMode</code>에 <code>PAGE_NOACCESS</code>를 지정해 줘야 한다.</p>
<ul>
<li>문서에는 <code>PAGE_READWRITE</code> 또는 <code>PAGE_READONLY</code>를 지정하라고 되어 있는데, 잘못된 설명이다. <em>(</em><code>MmSecureVirtualMemory</code> API의 설명을 그대로 가져오면서 오류가 생긴 것으로 추정된다.)</li>
</ul>
</li>
</ul>
<p>유사 핸들값 <em>(실제 핸들은 아니다)</em> 을 반환하는데, 나중에 보호 해제 시 필요하니 어딘가에 저장해 두도록 하자.</p>
<h2 id="heading-66mu66qo66asiouzto2yucdtlbtsojw">메모리 보호 해제</h2>
<p>위와 동일하게 대상 프로세스의 콘텍스트로 전환한 뒤, 2번 과정에서 반환된 핸들을 가지고 <a target="_blank" href="https://learn.microsoft.com/ko-kr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-mmunsecurevirtualmemory"><code>MmUnsecureVirtualMemory</code></a> API를 호출해 주면 된다.</p>
<pre><code class="lang-cpp">::MmUnsecureVirtualMemory(secure_handle);
</code></pre>
<h1 id="heading-7iuc7jew">시연</h1>
<ul>
<li><p>보호 적용</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700494028418/f57f61d0-72fa-4a45-8103-149e350db5c7.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>보호 해제</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700494040776/e30e7f9f-7e26-4222-b726-8f2fffa68fbb.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h1 id="heading-7jii7iucioy9loutna">예시 코드</h1>
<p>예시 코드에는 C++과 마이크로소프트의 <a target="_blank" href="https://github.com/microsoft/wil">WIL</a> 라이브러리를 사용했다.</p>
<ul>
<li>xil.hpp</li>
</ul>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">pragma</span> once</span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;ntifs.h&gt;</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;wil/resource.h&gt;</span></span>

<span class="hljs-keyword">namespace</span> xil
{
    <span class="hljs-keyword">namespace</span> detail
    {
        _IRQL_requires_max_(DISPATCH_LEVEL)
        <span class="hljs-function">_IRQL_requires_same_
        <span class="hljs-keyword">inline</span> <span class="hljs-keyword">void</span> __stdcall <span class="hljs-title">DereferenceObject</span><span class="hljs-params">(_In_ PVOID object)</span>
        </span>{
            ::ObDereferenceObject(object);
        }
    } <span class="hljs-comment">// namespace detail</span>

    <span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">typename</span> ObjectType&gt;
    <span class="hljs-keyword">using</span> unique_kernel_object_reference =
        wil::unique_any&lt;ObjectType,
                        <span class="hljs-keyword">decltype</span>(&amp;detail::DereferenceObject),
                        detail::DereferenceObject&gt;;

    <span class="hljs-keyword">using</span> unique_process = unique_kernel_object_reference&lt;PEPROCESS&gt;;
} <span class="hljs-comment">// namespace xil</span>
</code></pre>
<ul>
<li>main.cpp</li>
</ul>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;ntifs.h&gt;</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;wil/resource.h&gt;</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"xil.hpp"</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> INIT  __declspec(code_seg(<span class="hljs-meta-string">"INIT"</span>))</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> PAGED __declspec(code_seg(<span class="hljs-meta-string">"PAGE"</span>))</span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> LOG(level, message, ...)                                       \
    DbgPrintEx(DPFLTR_IHVDRIVER_ID,                                    \
               DPFLTR_ERROR_LEVEL,                                     \
               <span class="hljs-meta-string">"[TEST] ["</span> #level <span class="hljs-meta-string">"] ["</span> __FILE__ <span class="hljs-meta-string">"(%d)] "</span> message <span class="hljs-meta-string">"\n"</span>, \
               __LINE__,                                               \
               ##__VA_ARGS__)</span>

<span class="hljs-keyword">const</span> HANDLE kTargetProcessId = UlongToHandle(<span class="hljs-number">11328</span>);

<span class="hljs-keyword">const</span> PVOID kAddress = <span class="hljs-keyword">reinterpret_cast</span>&lt;PVOID&gt;(<span class="hljs-number">0x00007FF6BC310000</span>);
<span class="hljs-keyword">const</span> SIZE_T kSize   = <span class="hljs-number">0x6A000</span>;

HANDLE secure_handle = <span class="hljs-literal">nullptr</span>;

_Function_class_(DRIVER_UNLOAD)
_IRQL_requires_(PASSIVE_LEVEL)
<span class="hljs-function">_IRQL_requires_same_
PAGED VOID <span class="hljs-title">DriverUnload</span><span class="hljs-params">([[maybe_unused]] _In_ PDRIVER_OBJECT driver_object)</span>
</span>{
    PAGED_CODE();

    xil::unique_process process;

    NTSTATUS status = ::PsLookupProcessByProcessId(kTargetProcessId, &amp;process);

    <span class="hljs-keyword">if</span> (!NT_SUCCESS(status))
    {
        LOG(ERROR, <span class="hljs-string">"PsLookupProcessByProcessId failed. (%08X)"</span>, status);

        <span class="hljs-keyword">return</span>;
    }

    KAPC_STATE apc_state = {};

    ::KeStackAttachProcess(process.get(), &amp;apc_state);

    <span class="hljs-keyword">auto</span> unstack_detach_process = wil::scope_exit(
        [&amp;]
        {
            ::KeUnstackDetachProcess(&amp;apc_state);
        });

    ::MmUnsecureVirtualMemory(secure_handle);

    LOG(INFO, <span class="hljs-string">"MmUnsecureVirtualMemory succeeded."</span>);
}

EXTERN_C
_Function_class_(DRIVER_INITIALIZE)
_IRQL_requires_same_
_IRQL_requires_(PASSIVE_LEVEL)
<span class="hljs-function">INIT NTSTATUS <span class="hljs-title">DriverEntry</span><span class="hljs-params">(_In_ PDRIVER_OBJECT driver_object,
                          [[maybe_unused]] _In_ PUNICODE_STRING registry_path)</span>
</span>{
    PAGED_CODE();

    xil::unique_process process;

    NTSTATUS status = ::PsLookupProcessByProcessId(kTargetProcessId, &amp;process);

    <span class="hljs-keyword">if</span> (!NT_SUCCESS(status))
    {
        LOG(ERROR, <span class="hljs-string">"PsLookupProcessByProcessId failed. (%08X)"</span>, status);

        <span class="hljs-keyword">return</span> status;
    }

    KAPC_STATE apc_state = {};

    ::KeStackAttachProcess(process.get(), &amp;apc_state);

    <span class="hljs-keyword">auto</span> unstack_detach_process = wil::scope_exit(
        [&amp;]() INIT
        {
            ::KeUnstackDetachProcess(&amp;apc_state);
        });

    secure_handle = ::MmSecureVirtualMemoryEx(kAddress,
                                              kSize,
                                              PAGE_NOACCESS,
                                              MM_SECURE_NO_CHANGE);

    <span class="hljs-keyword">if</span> (!secure_handle)
    {
        LOG(ERROR, <span class="hljs-string">"MmSecureVirtualMemoryEx failed."</span>);

        <span class="hljs-keyword">return</span> STATUS_UNSUCCESSFUL;
    }

    LOG(INFO, <span class="hljs-string">"MmSecureVirtualMemoryEx succeeded."</span>);

    driver_object-&gt;DriverUnload = &amp;DriverUnload;

    <span class="hljs-keyword">return</span> STATUS_SUCCESS;
}
</code></pre>
<p>편의 상 프로세스 아이디 등은 하드코딩해 사용했다.</p>
<h1 id="heading-66ei7lmy66mw">마치며</h1>
<p>페이지 보호 속성 변경을 막아 프로세스를 보호한다는 아이디어는 꽤나 오래된 아이디어이고, 의외로 유저 모드에서 이를 수행할 수 있는 방법까지 존재한다. <em>(아쉽게도 문서화는 안 되어 있다.)</em></p>
<p><code>SEC_NO_CHANGE</code> 라는 플래그를 사용하는 방법인데, 아래 Github 프로젝트들을 참고하면 좋다.</p>
<ul>
<li><p><a target="_blank" href="https://github.com/changeofpace/Self-Remapping-Code">Self-Remapping-Code</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/chztbby/RebirthGuard">RebirthGuard</a> <em>(이건 한국인이 만든 프로젝트이다.)</em></p>
</li>
</ul>
<p>라온화이트햇에서도 관련 내용으로 포스팅을 한 적이 있다.</p>
<ul>
<li><a target="_blank" href="https://core-research-team.github.io/2020-06-01/Copy-On-Write-Global-Dll-injection">Copy-On-Write 페이지 조작을 이용한 Global Dll injection</a></li>
</ul>
<p><code>SEC_NO_CHANGE</code> 플래그를 활용한 방식과 <code>MmSecureVirtualMemoryEx</code> API를 사용한 방식의 장단점을 표로 정리해 보자면 아래와 같다.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td><code>SEC_NO_CHANGE</code></td><td><code>MmSecureVirtualMemoryEx</code></td></tr>
</thead>
<tbody>
<tr>
<td>유저 모드 사용</td><td>✔</td><td>❌</td></tr>
<tr>
<td>문서화 여부</td><td>❌</td><td>✔</td></tr>
<tr>
<td>커널 모드 호출자 예외</td><td>❌</td><td>✔</td></tr>
<tr>
<td>사용법</td><td>복잡</td><td>간단</td></tr>
</tbody>
</table>
</div><p>분명 <code>SEC_NO_CHANGE</code> 플래그의 유저 모드에서 사용 가능하다는 점은 나머지 단점들을 모조리 상쇄할 만큼 충분히 매력적이지만, 커널 모드가 가능한 상황이라면 무조건 <code>MmSecureVirtualMemoryEx</code> API를 선택할 정도로 종합적인 평가는 <code>MmSecureVirtualMemoryEx</code> 쪽이 우수하다.</p>
<p>안티 바이러스나 게임 안티 치트 등 보안 솔루션에서 특히 유용하게 사용할 수 있을 것으로 보인다.</p>
]]></content:encoded></item><item><title><![CDATA[Hashnode에 커스텀 CSS 적용하기]]></title><description><![CDATA[들어가며
Hashnode는 기본 스타일이 마음에 들지 않을 경우 사용자가 직접 커스터마이징할 수 있도록 커스텀 CSS 기능을 지원한다.
내 경우에는 Hashnode의 다크 테마가 마음에 들지 않아서 이 기능이 필요했다.

Hashnode에서 기본 제공하는 다크 테마는 Hashnode의 브랜드 컬러를 반영한 것인지, 지나치게 푸르딩딩 (?) 한 미드나이트 블루 색상을 사용하고 있었다.
나는 직접 커스텀 CSS를 작성해서 수정했는데, 수정하면서 H...]]></description><link>https://hakujitsu.hashnode.dev/applying-custom-css-to-hashnode</link><guid isPermaLink="true">https://hakujitsu.hashnode.dev/applying-custom-css-to-hashnode</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Shin Jinhyeok]]></dc:creator><pubDate>Mon, 20 Nov 2023 00:57:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1700441811101/01e47541-b300-467c-9f89-775d3e3cf103.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-65ok7ja06rca66mw">들어가며</h1>
<p>Hashnode는 기본 스타일이 마음에 들지 않을 경우 사용자가 직접 커스터마이징할 수 있도록 커스텀 CSS 기능을 지원한다.</p>
<p>내 경우에는 Hashnode의 다크 테마가 마음에 들지 않아서 이 기능이 필요했다.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699805092616/142252f0-bb59-4637-b85c-1d65099af1a0.png" alt class="image--center mx-auto" /></p>
<p>Hashnode에서 기본 제공하는 다크 테마는 Hashnode의 브랜드 컬러를 반영한 것인지, 지나치게 푸르딩딩 <em>(?)</em> 한 미드나이트 블루 색상을 사용하고 있었다.</p>
<p>나는 직접 커스텀 CSS를 작성해서 수정했는데, 수정하면서 Hashnode의 커스텀 CSS에 관해 다룬 자료도 많지 않고, 다른 사용자들이 만들어서 공유한 CSS도 전무하다시피 하다는 점이 꽤나 아쉬웠다.</p>
<p>이 포스팅에선 Hashnode의 커스텀 CSS 기능에 대해서도 다룰 겸, 내가 사용한 CSS와 작성 과정을 공유해 보려고 한다.</p>
<h1 id="heading-7kcb7jqpiouwqeuylq">적용 방법</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700444721075/9d3a953e-8738-4cac-962e-1ebba3f72299.png" alt class="image--center mx-auto" /></p>
<p>블로그 홈에 들어가면 헤더 오른편에 <code>Dashboard</code> 버튼이 보인다.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700414971932/ba582c12-4756-454d-b28e-69713f719f34.png" alt class="image--center mx-auto" /></p>
<p>대시보드에 들어가면 사이드 패널에 <code>Appearance</code> 라는 메뉴가 보일 텐데, 여기로 들어가 준다.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700415115523/dfa35e28-f09b-4ad5-beb2-3342eaa7f37b.png" alt class="image--center mx-auto" /></p>
<p>아래로 내리다 보면 <code>Custom CSS</code> 메뉴가 보인다. <code>Edit Custom Stylesheet</code> 버튼을 눌러서 커스텀 CSS를 편집할 수 있다.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700417097568/e5ee8400-bf70-4fdd-8ea1-16cbdf5e3636.png" alt class="image--center mx-auto" /></p>
<p>CSS는 크게 세 가지로 나눠서 적용할 수 있도록 되어 있다.</p>
<ul>
<li><p><code>Home</code></p>
<ul>
<li>블로그 홈에서 적용된다.</li>
</ul>
</li>
<li><p><code>Articles</code></p>
<ul>
<li>게시글에서 적용된다.</li>
</ul>
</li>
<li><p><code>Pages</code></p>
<ul>
<li>페이지에서 적용된다.</li>
</ul>
</li>
</ul>
<p>여기서 페이지가 무엇을 의미하는지 의아할 수 있다.</p>
<p>페이지란 블로그 대시보드의 <code>Pages</code> 메뉴에서 추가할 수 있는 페이지들을 이야기한다. 아마 별다른 설정을 하지 않았을 경우 <code>Badges</code>와 <code>Newsletter</code> 페이지가 기본으로 추가되어 있을 것이다.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700478977107/3a8814b1-2a4d-46e5-bddf-1b1d6628fc82.png" alt class="image--center mx-auto" /></p>
<p>이렇게 추가된 페이지들은 블로그 헤더에서 <code>Home</code> 우측에 차례로 표시된다.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700418977392/a11f5dd6-8dcb-476f-b436-3fd97cb8fb85.png" alt class="image--center mx-auto" /></p>
<p>페이지 하단을 보면 몇 가지 버튼이 있는데, 각 버튼의 기능은 아래와 같다.</p>
<ul>
<li><p><code>Publish</code></p>
<ul>
<li><p>CSS를 저장하고 실제 적용한다.</p>
</li>
<li><p>블로그 방문자들에게 적용된다.</p>
</li>
</ul>
</li>
<li><p><code>Reset</code></p>
<ul>
<li>CSS를 가장 최근에 <code>Publish</code> 했던 상태로 되돌린다.</li>
</ul>
</li>
<li><p><code>Preview</code></p>
<ul>
<li><p>CSS를 미리보기 한다.</p>
</li>
<li><p><code>Save Styles</code> 버튼을 눌러 CSS를 저장한 뒤 확인해야 한다.</p>
</li>
</ul>
</li>
<li><p><code>Save Styles</code></p>
<ul>
<li><p>CSS를 저장한다.</p>
</li>
<li><p>미리보기에만 적용된다.</p>
</li>
<li><p>페이지를 나가도 유지된다.</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-7j6r7isxiouwqeuylq">작성 방법</h1>
<h2 id="heading-css">커스텀 CSS용 클래스를 지정하는 방법</h2>
<p>Hashnode에서 커스텀 CSS 기능 지원을 위해 정의해 둔 클래스들이 존재한다.</p>
<ul>
<li><p><code>.blog-*</code></p>
<ul>
<li><code>.blog-header</code>, <code>.blog-title</code>, <code>.blog-main-logo</code>, <code>.blog-author-area</code>, <code>.blog-content-area</code>, <code>.blog-footer-area</code>, ...</li>
</ul>
</li>
<li><p><code>.dark</code></p>
<ul>
<li>다크 테마 스타일을 수정할 때 사용</li>
</ul>
</li>
</ul>
<p>간단한 스타일 수정이라면 이러한 클래스를 사용해 작업할 수 있다.</p>
<h2 id="heading-7keb7kcrioyimoygle2vocdsmptshozrpbwg7lc7jweioyngoygle2vmouklcdrsknrspu">직접 수정할 요소를 찾아 지정하는 방법</h2>
<p>좀 더 복잡한 작업을 하려면 <em>(개발자 도구 등을 사용해서)</em> 수정하고자 하는 요소를 찾아 직접 선택자를 작성해 줘야 한다.</p>
<p>이 방법은 자유도가 훨씬 높지만, 그만큼 신경 써 줘야 할 것도 늘어난다.</p>
<ul>
<li><p>어느 날 갑자기 작동하지 않을 수 있다.</p>
<ul>
<li><p>Hashnode 업데이트로 인해 HTML이나 CSS가 변경된다면 기존에는 잘 작동했던 것이 갑자기 작동하지 않게 될 가능성이 있다.</p>
</li>
<li><p>적당히 눈치껏 잘 안 바뀌겠다 싶은 것만 골라서 선택자를 작성해야 한다.</p>
</li>
</ul>
</li>
<li><p>CSS 우선순위가 꼬이기 쉽다.</p>
<ul>
<li>CSS 우선순위 때문에 거의 필연적으로 <code>!important</code> 키워드를 사용하게 될 텐데, 이것 때문에 우선순위 꼬이기가 굉장히 쉽다.</li>
</ul>
</li>
</ul>
<p>다행히 Hashnode는 <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a>를 사용하는 것으로 보이고, 클래스 명이 난독화되어 있거나 하지도 않다. 잘만 작성한다면 유지 보수가 그렇게 힘들 것 같진 않다.</p>
<h1 id="heading-7jii7iuc">예시</h1>
<p>예시로 이 블로그에 사용된 커스텀 CSS를 공유해 보고자 한다.</p>
<blockquote>
<p><strong>Disclaimer</strong></p>
<p>먼저, 나는 프론트 개발자가 아니라는 점을 밝힌다.</p>
<p>이 방식보다 더 나은 방식이 충분히 존재할 수 있다. 만약 수정하고자 하는 부분이 있다면 댓글 남겨주시면 반영하도록 하겠다.</p>
</blockquote>
<pre><code class="lang-css"><span class="hljs-comment">/* General */</span>

<span class="hljs-comment">/* Light Theme */</span>

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.border-slate-100</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">241</span> <span class="hljs-number">241</span> <span class="hljs-number">241</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.border-slate-200</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.border-slate-300</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">203</span> <span class="hljs-number">203</span> <span class="hljs-number">203</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.border-slate-50</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.border-slate-800</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.border-slate-900</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.bg-slate-100</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">241</span> <span class="hljs-number">241</span> <span class="hljs-number">241</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.bg-slate-200</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.bg-slate-50</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.bg-slate-800</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.bg-slate-900</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.stroke-slate-300</span> {
  <span class="hljs-attribute">stroke</span>:<span class="hljs-number">#cbcbcb</span><span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-100</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">241</span> <span class="hljs-number">241</span> <span class="hljs-number">241</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-300</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">203</span> <span class="hljs-number">203</span> <span class="hljs-number">203</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-400</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">148</span> <span class="hljs-number">148</span> <span class="hljs-number">148</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-500</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">100</span> <span class="hljs-number">100</span> <span class="hljs-number">100</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-600</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">71</span> <span class="hljs-number">71</span> <span class="hljs-number">71</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-700</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-800</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.text-slate-900</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.placeholder-slate-500</span><span class="hljs-selector-pseudo">::-moz-placeholder</span> {
  <span class="hljs-attribute">--tw-placeholder-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">100</span> <span class="hljs-number">100</span> <span class="hljs-number">100</span>/var(--tw-placeholder-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.placeholder-slate-500</span><span class="hljs-selector-pseudo">::placeholder</span> {
  <span class="hljs-attribute">--tw-placeholder-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">100</span> <span class="hljs-number">100</span> <span class="hljs-number">100</span>/var(--tw-placeholder-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.ring-slate-950</span>\/80 {
  <span class="hljs-attribute">--tw-ring-color</span>:<span class="hljs-built_in">rgba</span>(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>,<span class="hljs-number">2</span>,.<span class="hljs-number">8</span>)<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:border-slate-200</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:border-slate-400</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">148</span> <span class="hljs-number">148</span> <span class="hljs-number">148</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:bg-slate-100</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">241</span> <span class="hljs-number">241</span> <span class="hljs-number">241</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:bg-slate-200</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:bg-slate-50</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:bg-slate-700</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:text-slate-900</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.focus</span>\<span class="hljs-selector-pseudo">:bg-slate-100</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">241</span> <span class="hljs-number">241</span> <span class="hljs-number">241</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:enabled</span>\<span class="hljs-selector-pseudo">:bg-slate-50</span><span class="hljs-selector-pseudo">:enabled</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.disabled</span>\<span class="hljs-selector-pseudo">:bg-slate-50</span><span class="hljs-selector-pseudo">:disabled</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.disabled</span>\<span class="hljs-selector-pseudo">:text-slate-300</span><span class="hljs-selector-pseudo">:disabled</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">203</span> <span class="hljs-number">203</span> <span class="hljs-number">203</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.group</span><span class="hljs-selector-pseudo">:hover</span> <span class="hljs-selector-class">.group-hover</span>\<span class="hljs-selector-pseudo">:border-slate-200</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.group</span><span class="hljs-selector-pseudo">:focus</span> <span class="hljs-selector-class">.group-focus</span>\<span class="hljs-selector-pseudo">:ring-slate-950</span>\/80 {
  <span class="hljs-attribute">--tw-ring-color</span>:<span class="hljs-built_in">rgba</span>(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>,<span class="hljs-number">2</span>,.<span class="hljs-number">8</span>)<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.prose</span> <span class="hljs-selector-pseudo">:where(td)</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-pseudo">:where(</span><span class="hljs-selector-attr">[class~=not-prose]</span> *)) {
  <span class="hljs-comment">/* table border */</span>
  <span class="hljs-attribute">border</span>:<span class="hljs-number">1px</span> solid <span class="hljs-built_in">rgba</span>(<span class="hljs-number">226</span>,<span class="hljs-number">226</span>,<span class="hljs-number">226</span>,.<span class="hljs-number">8</span>)<span class="hljs-meta">!important</span>
}

<span class="hljs-comment">/* Dark Theme */</span>

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:border-slate-200)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:border-slate-50)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:border-slate-500)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">100</span> <span class="hljs-number">100</span> <span class="hljs-number">100</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:border-slate-600)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">71</span> <span class="hljs-number">71</span> <span class="hljs-number">71</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:border-slate-700)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:border-slate-800)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>;
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:border-slate-900)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-100)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">241</span> <span class="hljs-number">241</span> <span class="hljs-number">241</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-200)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-50)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-600)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">71</span> <span class="hljs-number">71</span> <span class="hljs-number">71</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-700)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-800)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-900)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:bg-slate-950)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">2</span> <span class="hljs-number">2</span> <span class="hljs-number">2</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:from-slate-800)</span> {
  <span class="hljs-attribute">--tw-gradient-from</span>:<span class="hljs-number">#1e1e1e</span> <span class="hljs-built_in">var</span>(--tw-gradient-from-position)<span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">--tw-gradient-to</span>:<span class="hljs-built_in">rgba</span>(<span class="hljs-number">30</span>,<span class="hljs-number">30</span>,<span class="hljs-number">30</span>,<span class="hljs-number">0</span>) <span class="hljs-built_in">var</span>(--tw-gradient-to-position)<span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">--tw-gradient-stops</span>:<span class="hljs-built_in">var</span>(--tw-gradient-from),<span class="hljs-built_in">var</span>(--tw-gradient-to)
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:from-slate-900)</span> {
  <span class="hljs-attribute">--tw-gradient-from</span>:<span class="hljs-number">#0f0f0f</span> <span class="hljs-built_in">var</span>(--tw-gradient-from-position)<span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">--tw-gradient-to</span>:<span class="hljs-built_in">rgba</span>(<span class="hljs-number">15</span>,<span class="hljs-number">15</span>,<span class="hljs-number">15</span>,<span class="hljs-number">0</span>) <span class="hljs-built_in">var</span>(--tw-gradient-to-position)<span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">--tw-gradient-stops</span>:<span class="hljs-built_in">var</span>(--tw-gradient-from),<span class="hljs-built_in">var</span>(--tw-gradient-to)
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-100)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">241</span> <span class="hljs-number">241</span> <span class="hljs-number">241</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-200)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span> <span class="hljs-number">226</span> <span class="hljs-number">226</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-300)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">203</span> <span class="hljs-number">203</span> <span class="hljs-number">203</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-400)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">148</span> <span class="hljs-number">148</span> <span class="hljs-number">148</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-50)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">248</span> <span class="hljs-number">248</span> <span class="hljs-number">248</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-500)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">100</span> <span class="hljs-number">100</span> <span class="hljs-number">100</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-600)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">71</span> <span class="hljs-number">71</span> <span class="hljs-number">71</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-700)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:text-slate-900)</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:placeholder-slate-400)</span><span class="hljs-selector-pseudo">::-moz-placeholder</span> {
  <span class="hljs-attribute">--tw-placeholder-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">148</span> <span class="hljs-number">148</span> <span class="hljs-number">148</span>/var(--tw-placeholder-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:placeholder-slate-400)</span><span class="hljs-selector-pseudo">::placeholder</span> {
  <span class="hljs-attribute">--tw-placeholder-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">148</span> <span class="hljs-number">148</span> <span class="hljs-number">148</span>/var(--tw-placeholder-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:ring-offset-slate-800)</span> {
  <span class="hljs-attribute">--tw-ring-offset-color</span>:<span class="hljs-number">#1e1e1e</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:hover</span>\<span class="hljs-selector-pseudo">:border-slate-500</span><span class="hljs-selector-pseudo">:hover)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">100</span> <span class="hljs-number">100</span> <span class="hljs-number">100</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:hover</span>\<span class="hljs-selector-pseudo">:border-slate-700</span><span class="hljs-selector-pseudo">:hover)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:hover</span>\<span class="hljs-selector-pseudo">:border-slate-800</span><span class="hljs-selector-pseudo">:hover)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:hover</span>\<span class="hljs-selector-pseudo">:bg-slate-300</span><span class="hljs-selector-pseudo">:hover)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">203</span> <span class="hljs-number">203</span> <span class="hljs-number">203</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:hover</span>\<span class="hljs-selector-pseudo">:bg-slate-700</span><span class="hljs-selector-pseudo">:hover)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:hover</span>\<span class="hljs-selector-pseudo">:bg-slate-800</span><span class="hljs-selector-pseudo">:hover)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:hover</span>\<span class="hljs-selector-pseudo">:bg-slate-900</span><span class="hljs-selector-pseudo">:hover)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:dark</span>\<span class="hljs-selector-pseudo">:bg-slate-700)</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.hover</span>\<span class="hljs-selector-pseudo">:dark</span>\<span class="hljs-selector-pseudo">:bg-slate-800)</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:focus</span>\<span class="hljs-selector-pseudo">:bg-slate-700</span><span class="hljs-selector-pseudo">:focus)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:focus</span>\<span class="hljs-selector-pseudo">:bg-slate-800</span><span class="hljs-selector-pseudo">:focus)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:focus</span>\<span class="hljs-selector-pseudo">:bg-slate-900</span><span class="hljs-selector-pseudo">:focus)</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:focus</span>\<span class="hljs-selector-pseudo">:ring-offset-slate-800</span><span class="hljs-selector-pseudo">:focus)</span> {
  <span class="hljs-attribute">--tw-ring-offset-color</span>:<span class="hljs-number">#1e1e1e</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:focus-visible</span>\<span class="hljs-selector-pseudo">:ring-offset-slate-800</span><span class="hljs-selector-pseudo">:focus-visible)</span> {
  <span class="hljs-attribute">--tw-ring-offset-color</span>:<span class="hljs-number">#1e1e1e</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:focus-visible</span>\<span class="hljs-selector-pseudo">:ring-offset-slate-900</span><span class="hljs-selector-pseudo">:focus-visible)</span> {
  <span class="hljs-attribute">--tw-ring-offset-color</span>:<span class="hljs-number">#0f0f0f</span><span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.disabled</span>\<span class="hljs-selector-pseudo">:dark</span>\<span class="hljs-selector-pseudo">:bg-slate-900)</span><span class="hljs-selector-pseudo">:disabled</span> {
  <span class="hljs-attribute">--tw-bg-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">background-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">15</span> <span class="hljs-number">15</span>/var(--tw-bg-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.disabled</span>\<span class="hljs-selector-pseudo">:dark</span>\<span class="hljs-selector-pseudo">:text-slate-400)</span><span class="hljs-selector-pseudo">:disabled</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">148</span> <span class="hljs-number">148</span> <span class="hljs-number">148</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.disabled</span>\<span class="hljs-selector-pseudo">:dark</span>\<span class="hljs-selector-pseudo">:text-slate-600)</span><span class="hljs-selector-pseudo">:disabled</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">71</span> <span class="hljs-number">71</span> <span class="hljs-number">71</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.disabled</span>\<span class="hljs-selector-pseudo">:dark</span>\<span class="hljs-selector-pseudo">:text-slate-800)</span><span class="hljs-selector-pseudo">:disabled</span> {
  <span class="hljs-attribute">--tw-text-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">30</span> <span class="hljs-number">30</span> <span class="hljs-number">30</span>/var(--tw-text-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-class">.group</span><span class="hljs-selector-pseudo">:hover</span> <span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.group-hover</span>\<span class="hljs-selector-pseudo">:dark</span>\<span class="hljs-selector-pseudo">:border-slate-700)</span> {
  <span class="hljs-attribute">--tw-border-opacity</span>:<span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-color</span>:<span class="hljs-built_in">rgb</span>(<span class="hljs-number">51</span> <span class="hljs-number">51</span> <span class="hljs-number">51</span>/var(--tw-border-opacity))<span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.group</span><span class="hljs-selector-pseudo">:focus</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:group-focus</span>\<span class="hljs-selector-pseudo">:ring-offset-slate-800)</span> {
  <span class="hljs-attribute">--tw-ring-offset-color</span>:<span class="hljs-number">#1e1e1e</span><span class="hljs-meta">!important</span>
}

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:prose-dark)</span> <span class="hljs-selector-pseudo">:where(td)</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-pseudo">:where(</span><span class="hljs-selector-attr">[class~=not-prose]</span> *)) {
  <span class="hljs-comment">/* table border */</span>
  <span class="hljs-attribute">border</span>:<span class="hljs-number">1px</span> solid <span class="hljs-number">#1e1e1e</span><span class="hljs-meta">!important</span>
}

<span class="hljs-comment">/* Syntax Highlighting */</span>

<span class="hljs-comment">/* Light Theme */</span>

<span class="hljs-selector-class">.prose</span> <span class="hljs-selector-pseudo">:where(pre)</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-pseudo">:where(</span><span class="hljs-selector-attr">[class~=not-prose]</span> *)) {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fbfcfd</span><span class="hljs-meta">!important</span>;
}
<span class="hljs-selector-class">.prose</span> <span class="hljs-selector-tag">pre</span> <span class="hljs-selector-tag">code</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#24292e</span><span class="hljs-meta">!important</span>;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-class">.absolute</span><span class="hljs-selector-class">.text-white</span> {
  <span class="hljs-comment">/* copy button */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span><span class="hljs-meta">!important</span>;
}

<span class="hljs-selector-tag">pre</span> <span class="hljs-selector-tag">code</span><span class="hljs-selector-class">.hljs</span> {
  <span class="hljs-attribute">display</span>: block;
  <span class="hljs-attribute">overflow-x</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>
}
<span class="hljs-selector-tag">code</span><span class="hljs-selector-class">.hljs</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">3px</span> <span class="hljs-number">5px</span>
}
<span class="hljs-comment">/*!
  Theme: GitHub
  Description: Light theme as seen on github.com
  Author: github.com
  Maintainer: @Hirse
  Updated: 2021-05-15

  Outdated base version: https://github.com/primer/github-syntax-light
  Current colors taken from GitHub's CSS
*/</span>
<span class="hljs-selector-class">.hljs</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#24292e</span>;
  <span class="hljs-comment">/* background: #ffffff */</span>
}
<span class="hljs-selector-class">.hljs-doctag</span>,
<span class="hljs-selector-class">.hljs-keyword</span>,
<span class="hljs-selector-class">.hljs-meta</span> <span class="hljs-selector-class">.hljs-keyword</span>,
<span class="hljs-selector-class">.hljs-template-tag</span>,
<span class="hljs-selector-class">.hljs-template-variable</span>,
<span class="hljs-selector-class">.hljs-type</span>,
<span class="hljs-selector-class">.hljs-variable</span><span class="hljs-selector-class">.language_</span> {
  <span class="hljs-comment">/* prettylights-syntax-keyword */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#d73a49</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-title</span>,
<span class="hljs-selector-class">.hljs-title</span><span class="hljs-selector-class">.class_</span>,
<span class="hljs-selector-class">.hljs-title</span><span class="hljs-selector-class">.class_</span><span class="hljs-selector-class">.inherited__</span>,
<span class="hljs-selector-class">.hljs-title</span><span class="hljs-selector-class">.function_</span> {
  <span class="hljs-comment">/* prettylights-syntax-entity */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#6f42c1</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-attr</span>,
<span class="hljs-selector-class">.hljs-attribute</span>,
<span class="hljs-selector-class">.hljs-literal</span>,
<span class="hljs-selector-class">.hljs-meta</span>,
<span class="hljs-selector-class">.hljs-number</span>,
<span class="hljs-selector-class">.hljs-operator</span>,
<span class="hljs-selector-class">.hljs-variable</span>,
<span class="hljs-selector-class">.hljs-selector-attr</span>,
<span class="hljs-selector-class">.hljs-selector-class</span>,
<span class="hljs-selector-class">.hljs-selector-id</span> {
  <span class="hljs-comment">/* prettylights-syntax-constant */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#005cc5</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-regexp</span>,
<span class="hljs-selector-class">.hljs-string</span>,
<span class="hljs-selector-class">.hljs-meta</span> <span class="hljs-selector-class">.hljs-string</span> {
  <span class="hljs-comment">/* prettylights-syntax-string */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#032f62</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-built_in</span>,
<span class="hljs-selector-class">.hljs-symbol</span> {
  <span class="hljs-comment">/* prettylights-syntax-variable */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#e36209</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-comment</span>,
<span class="hljs-selector-class">.hljs-code</span>,
<span class="hljs-selector-class">.hljs-formula</span> {
  <span class="hljs-comment">/* prettylights-syntax-comment */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#6a737d</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-name</span>,
<span class="hljs-selector-class">.hljs-quote</span>,
<span class="hljs-selector-class">.hljs-selector-tag</span>,
<span class="hljs-selector-class">.hljs-selector-pseudo</span> {
  <span class="hljs-comment">/* prettylights-syntax-entity-tag */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#22863a</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-subst</span> {
  <span class="hljs-comment">/* prettylights-syntax-storage-modifier-import */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#24292e</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-section</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-heading */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#005cc5</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">font-weight</span>: bold<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-bullet</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-list */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#735c0f</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-emphasis</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-italic */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#24292e</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">font-style</span>: italic<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-strong</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-bold */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#24292e</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">font-weight</span>: bold<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-addition</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-inserted */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#22863a</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0fff4</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-deletion</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-deleted */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#b31d28</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffeef0</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.hljs-char</span><span class="hljs-selector-class">.escape_</span>,
<span class="hljs-selector-class">.hljs-link</span>,
<span class="hljs-selector-class">.hljs-params</span>,
<span class="hljs-selector-class">.hljs-property</span>,
<span class="hljs-selector-class">.hljs-punctuation</span>,
<span class="hljs-selector-class">.hljs-tag</span> {
  <span class="hljs-comment">/* purposely ignored */</span>

}

<span class="hljs-comment">/* Dark Theme */</span>

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:prose-dark)</span> <span class="hljs-selector-pseudo">:where(pre)</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-pseudo">:where(</span><span class="hljs-selector-attr">[class~=<span class="hljs-string">"not-prose"</span>]</span> *)) {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#1e1e1e</span><span class="hljs-meta">!important</span>;
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.prose</span> <span class="hljs-selector-tag">pre</span> <span class="hljs-selector-tag">code</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#c9d1d9</span><span class="hljs-meta">!important</span>;
}

<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-tag">button</span><span class="hljs-selector-class">.absolute</span><span class="hljs-selector-class">.text-white</span> {
  <span class="hljs-comment">/* copy button */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span><span class="hljs-meta">!important</span>;
}

<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-tag">pre</span> <span class="hljs-selector-tag">code</span><span class="hljs-selector-class">.hljs</span> {
  <span class="hljs-attribute">display</span>: block;
  <span class="hljs-attribute">overflow-x</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-tag">code</span><span class="hljs-selector-class">.hljs</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">3px</span> <span class="hljs-number">5px</span>
}
<span class="hljs-comment">/*!
  Theme: GitHub Dark
  Description: Dark theme as seen on github.com
  Author: github.com
  Maintainer: @Hirse
  Updated: 2021-05-15

  Outdated base version: https://github.com/primer/github-syntax-dark
  Current colors taken from GitHub's CSS
*/</span>
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#c9d1d9</span>;
  <span class="hljs-comment">/* background: #0d1117 */</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-doctag</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-keyword</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-meta</span> <span class="hljs-selector-class">.hljs-keyword</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-template-tag</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-template-variable</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-type</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-variable</span><span class="hljs-selector-class">.language_</span> {
  <span class="hljs-comment">/* prettylights-syntax-keyword */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#ff7b72</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-title</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-title</span><span class="hljs-selector-class">.class_</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-title</span><span class="hljs-selector-class">.class_</span><span class="hljs-selector-class">.inherited__</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-title</span><span class="hljs-selector-class">.function_</span> {
  <span class="hljs-comment">/* prettylights-syntax-entity */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#d2a8ff</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-attr</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-attribute</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-literal</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-meta</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-number</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-operator</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-variable</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-selector-attr</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-selector-class</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-selector-id</span> {
  <span class="hljs-comment">/* prettylights-syntax-constant */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#79c0ff</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-regexp</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-string</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-meta</span> <span class="hljs-selector-class">.hljs-string</span> {
  <span class="hljs-comment">/* prettylights-syntax-string */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#a5d6ff</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-built_in</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-symbol</span> {
  <span class="hljs-comment">/* prettylights-syntax-variable */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffa657</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-comment</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-code</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-formula</span> {
  <span class="hljs-comment">/* prettylights-syntax-comment */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#8b949e</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-name</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-quote</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-selector-tag</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-selector-pseudo</span> {
  <span class="hljs-comment">/* prettylights-syntax-entity-tag */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#7ee787</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-subst</span> {
  <span class="hljs-comment">/* prettylights-syntax-storage-modifier-import */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#c9d1d9</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-section</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-heading */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#1f6feb</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">font-weight</span>: bold<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-bullet</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-list */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#f2cc60</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-emphasis</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-italic */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#c9d1d9</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">font-style</span>: italic<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-strong</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-bold */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#c9d1d9</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">font-weight</span>: bold<span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-addition</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-inserted */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#aff5b4</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#033a16</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-deletion</span> {
  <span class="hljs-comment">/* prettylights-syntax-markup-deleted */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffdcd7</span><span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#67060c</span><span class="hljs-meta">!important</span>
}
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-char</span><span class="hljs-selector-class">.escape_</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-link</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-params</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-property</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-punctuation</span>,
<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-class">.hljs-tag</span> {
  <span class="hljs-comment">/* purposely ignored */</span>

}
</code></pre>
<h2 id="heading-7j6r7isxioqzvoyglq">작성 과정</h2>
<h3 id="heading-6riw67o4ioydieydgsdrs4dqsr0">기본 색상 변경</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700434079289/645d3e63-83df-4270-baee-734c30415796.png" alt class="image--center mx-auto" /></p>
<p>개발자 도구로 '푸르딩딩'한 색깔을 가진 요소를 조사해 보면 Tailwind CSS의 slate 색상을 사용하고 있는 것을 확인할 수 있다.</p>
<p>Hashnode의 스타일시트를 내려받아 <code>-slate</code>를 검색해 slate 색상을 사용 중인 모든 CSS 규칙들을 복사해 주도록 한다. <em>(파이어폭스의 경우 스타일 편집기 탭에서 가져오면 되고, 크로뮴 기반 브라우저의 경우 네트워크 탭에서 가져오면 될 것으로 보인다.)</em></p>
<p>다음으로 아래 정규표현식을 사용해서 색상을 전부 무채색으로 만들어 주면 된다. <em>(VS Code의 Replace All 기능을 사용했다.)</em></p>
<ol>
<li><p><code>#(\w{2})\w{4}</code> → <code>#$1$1$1</code></p>
</li>
<li><p><code>(rgba?)\((\d+)( *,? *)\d+( *,? *)\d+</code> → <code>$1($2$3$2$4$2</code></p>
</li>
<li><p><code>((?:(?:rgba?)|#)[^;]*)</code> → <code>$1!important</code></p>
</li>
</ol>
<p><code>#xxxxxx</code>, <code>rgb</code>, <code>rgba</code> 형식의 색상들에서 녹색과 파란색을 모두 빨간색과 동일하게 설정해 주었다.</p>
<p>사실 Tailwind CSS의 공식 문서를 보면 <a target="_blank" href="https://tailwindcss.com/docs/background-color">색상표</a>가 있고, 여기서 neutral 계열이 무채색에 해당하는데, 각 slate 색상을 대응하는 neutral 색상으로 변경해 주는 게 더 좋다. 근데 나는 이게 귀찮아서 그냥 정규표현식으로 치환했다...</p>
<p>여기까지만 하면 다크 테마의 일부 색상이 라이트 테마의 색상으로 적용되어 있을 것이다.</p>
<p><code>!important</code> 키워드의 부작용인데, 달리 해결할 방법이 없는 것 같아 단순히 라이트 테마 규칙들의 선택자 앞에 <code>html:not(.dark)</code>를 추가해 줬다. 아래 정규표현식을 사용하면 된다.</p>
<ul>
<li><code>(.+\{)</code> → <code>html:not(.dark) $1</code></li>
</ul>
<h3 id="heading-6rws66y4ioqwleyhscdthyzrp4gg67oa6rk9">구문 강조 테마 변경</h3>
<p>다음으로는 구문 강조 <em>(Syntax Highlighting)</em> 테마를 변경해 줘야 한다.</p>
<p>Hashnode의 경우 구문 강조를 위해 <a target="_blank" href="https://highlightjs.org/">highlight.js</a>를 사용한다. <a target="_blank" href="https://highlightjs.org/demo">데모 페이지</a>에서 마음에 드는 테마를 찾아 고른 뒤 <em>(라이트 테마, 다크 테마 두 개 정도 고르면 좋다.)</em> <a target="_blank" href="https://github.com/highlightjs/highlight.js/tree/main/src/styles">이곳</a>에서 CSS를 가져오면 된다.</p>
<p>가져온 CSS에 <code>!important</code> 키워드를 추가해서 작성 중인 커스텀 CSS에 넣고, 다크 테마에 적용할 속성의 경우 <code>.hljs-*</code> 앞에 <code>.dark</code>를 붙여 주면 된다.</p>
<p>이때 주의할 점은 Hashnode에서 <em>(왜인진 모르겠으나)</em> <code>.hljs</code> 클래스를 사용하지 않는다는 것이다. 따라서 <code>.hljs</code>에 정의된 글자 색상과 배경 색상을 다른 곳으로 옮겨 줘야 한다.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>라이트</td><td>다크</td></tr>
</thead>
<tbody>
<tr>
<td>글자</td><td><code>.prose pre code</code></td><td><code>.dark .prose pre code</code></td></tr>
<tr>
<td>배경</td><td><code>.prose :where(pre):not(:where([class~=not-prose] *))</code></td><td><code>:is(.dark .dark:prose-dark) :where(pre):not(:where([class~="not-prose"] *))</code></td></tr>
</tbody>
</table>
</div><p>마지막으로, 코드 블록 배경색이 밝은 색상이라면 코드 복사 버튼이 잘 보이지 않을 것이다. 이를 해결하기 위해 아래 CSS를 추가해 준다.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Light Theme */</span>

<span class="hljs-selector-tag">button</span><span class="hljs-selector-class">.absolute</span><span class="hljs-selector-class">.text-white</span> {
  <span class="hljs-comment">/* copy button */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span><span class="hljs-meta">!important</span>;
}

<span class="hljs-comment">/* Dark Theme */</span>

<span class="hljs-selector-class">.dark</span> <span class="hljs-selector-tag">button</span><span class="hljs-selector-class">.absolute</span><span class="hljs-selector-class">.text-white</span> {
  <span class="hljs-comment">/* copy button */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span><span class="hljs-meta">!important</span>;
}
</code></pre>
<h3 id="heading-6riw7yoaioydieydgsdrs4dqsr0">기타 색상 변경</h3>
<p>파인 튜닝 과정이다.</p>
<p>위 내용들로도 충분하여 수정할 부분이 많지는 않았으나, 글에 표를 삽입했을 때 표 테두리 색상이 여전히 파란 계열이어서 이 부분만 추가로 수정해 주었다.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Light Theme */</span>

<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:not(.dark)</span> <span class="hljs-selector-class">.prose</span> <span class="hljs-selector-pseudo">:where(td)</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-pseudo">:where(</span><span class="hljs-selector-attr">[class~=not-prose]</span> *)) {
  <span class="hljs-comment">/* table border */</span>
  <span class="hljs-attribute">border</span>:<span class="hljs-number">1px</span> solid <span class="hljs-built_in">rgba</span>(<span class="hljs-number">226</span>,<span class="hljs-number">226</span>,<span class="hljs-number">226</span>,.<span class="hljs-number">8</span>)<span class="hljs-meta">!important</span>
}

<span class="hljs-comment">/* Dark Theme */</span>

<span class="hljs-selector-pseudo">:is(.dark</span> <span class="hljs-selector-class">.dark</span>\<span class="hljs-selector-pseudo">:prose-dark)</span> <span class="hljs-selector-pseudo">:where(td)</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-pseudo">:where(</span><span class="hljs-selector-attr">[class~=not-prose]</span> *)) {
  <span class="hljs-comment">/* table border */</span>
  <span class="hljs-attribute">border</span>:<span class="hljs-number">1px</span> solid <span class="hljs-number">#1e1e1e</span><span class="hljs-meta">!important</span>
}
</code></pre>
<h1 id="heading-66ei7lmy66mw">마치며</h1>
<p>이상으로 Hashnode에 커스텀 CSS를 적용하는 방법에 대해서 알아보았다.</p>
<p>이 글이 부디 도움이 되었기를 바란다.</p>
<h1 id="heading-6rsa66coioyekoujja">관련 자료</h1>
<ul>
<li><a target="_blank" href="https://hashnode.com/post/style-your-hashnode-blog-with-custom-css">Style your Hashnode blog with Custom CSS</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Velog vs. Hashnode]]></title><description><![CDATA[들어가며
구글에 'Hashnode'를 검색해 보면 다른 Hashnode 사용자들이 자신이 왜 기술 블로그 플랫폼으로 Hashnode를 선택했는지, 이유를 설명하는 글들을 많이 찾아볼 수 있다.
내가 기술 블로그 플랫폼을 선택하는 과정에서 그런 글들의 도움을 많이 받기도 했고, (앞으로 주로 쓸 내용에 비하면) 비교적 접근성이 좋은 주제인 것 같아 나도 써보기로 했다.
왜 Hashnode인가?
고려했던 플랫폼들
내가 기술 블로그를 시작하기 전 고...]]></description><link>https://hakujitsu.hashnode.dev/velog-vs-hashnode</link><guid isPermaLink="true">https://hakujitsu.hashnode.dev/velog-vs-hashnode</guid><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Shin Jinhyeok]]></dc:creator><pubDate>Sun, 12 Nov 2023 01:51:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1699754222645/9af6b95c-2368-49c6-8610-c288a732c477.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-65ok7ja06rca66mw">들어가며</h1>
<p>구글에 'Hashnode'를 검색해 보면 다른 Hashnode 사용자들이 자신이 왜 기술 블로그 플랫폼으로 Hashnode를 선택했는지, 이유를 설명하는 글들을 많이 찾아볼 수 있다.</p>
<p>내가 기술 블로그 플랫폼을 선택하는 과정에서 그런 글들의 도움을 많이 받기도 했고, <em>(앞으로 주로 쓸 내용에 비하면)</em> 비교적 접근성이 좋은 주제인 것 같아 나도 써보기로 했다.</p>
<h1 id="heading-hashnode">왜 Hashnode인가?</h1>
<h2 id="heading-6rog66ck7zai642yio2ujoueq2pvoutpa">고려했던 플랫폼들</h2>
<p>내가 기술 블로그를 시작하기 전 고려했던 플랫폼들에는 몇 가지가 있었다.</p>
<ul>
<li><p>Velog</p>
</li>
<li><p>Hashnode</p>
</li>
<li><p>Medium</p>
</li>
<li><p>Github Pages</p>
</li>
</ul>
<p>솔직히 내가 나를 아는데, Github으로 블로그를 관리하면 귀찮아서 금방 글을 안 올리게 될 것이 뻔했다. 그래서 Github은 후보에서 제외했다.</p>
<p>Medium은 한글 폰트가 명조체로 나오는 것이 마음에 안 들었고, 이외에도 마크다운 미지원, 구문 강조 <em>(Syntax Highlighting)</em> 기능 미지원 등의 사유로 후보에서 제외하였다.</p>
<p>남은 건 Velog와 Hashnode인데, 사실은 이미 Velog를 사용하기로 결정하고 글도 하나 작성해 보았었다.</p>
<p><strong>그러나 결국 Hashnode로 도망쳐 나왔다.</strong></p>
<h2 id="heading-velog">Velog를 포기한 이유</h2>
<p>막상 Velog를 사용해 보니 생각했던 것만큼 그렇게 좋지는 않았다.</p>
<ul>
<li><p>흔하다.</p>
<ul>
<li><p>속물 효과, 쉬운 말로는 홍대병</p>
</li>
<li><p>한국 한정 Hashnode는 충분히 힙한 플랫폼인 것 같다.</p>
</li>
</ul>
</li>
<li><p>버그가 많다.</p>
<ul>
<li><p>파이어폭스라서 그런 건지는 모르겠으나, 나의 경우 작성 도중 글의 일부분을 선택하려고 드래그하면 선택된 영역의 글이 스르륵 지워지는 문제가 있었다.</p>
</li>
<li><p>어쩔 땐 커서를 옮기면 마지막에 쓴 글자가 지워지기도 했다.</p>
</li>
<li><p>글 수정이 잘 안 된다. 글을 수정하고 수정하기 버튼을 눌러도 아무런 반응이 없는 경우가 꽤 있었다.</p>
</li>
</ul>
</li>
</ul>
<p>Velog를 사용하기로 결심했던 만큼 '흔하다'는 점 정도는 어느정도 감안하고 넘어가려 했으나, 고작 글 하나를 작성했을 뿐인데도 자잘한 버그가 생각보다 너무 많이 보여서 결국 이주를 결정하게 되었다.</p>
<h1 id="heading-hashnode-1">Hashnode의 장점</h1>
<p>Hashnode로 이주하고 느낀 장점은 꽤나 많았다.</p>
<ul>
<li><p>Velog에서 겪던 문제가 사라졌다.</p>
<ul>
<li>힙하고, 버그도 적고, ...</li>
</ul>
</li>
<li><p>예쁘다.</p>
<ul>
<li><p>특히 상단 헤더의 반투명 효과가 마음에 든다.</p>
<ul>
<li>WinUI3에선 아크릴릭 효과라고 불렀었는데... 일반적으론 뭐라고 부르는지 모르겠다.</li>
</ul>
</li>
<li><p>확실히 Velog보단 화려한 느낌이다.</p>
</li>
<li><p>Velog의 마크다운 표 디자인은 상당히 이상했었는데, Hashnode의 표 디자인은 멀쩡하다.</p>
</li>
</ul>
</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>열1</td><td>열2</td></tr>
</thead>
<tbody>
<tr>
<td>이런</td><td>느낌이다.</td></tr>
</tbody>
</table>
</div><ul>
<li><p>커스터마이징이 자유롭다.</p>
<ul>
<li><p><em>(당연하게도)</em> Github 블로그보단 제한적이다.</p>
</li>
<li><p>그래도 커스텀 CSS를 지원하여 기본 스타일이 마음에 들지 않으면 직접 수정할 수 있게 해뒀단 점은 칭찬할 만하다.</p>
</li>
<li><p>블로그 홈 화면 레이아웃도 매거진, 스택, 그리드 레이아웃 중에서 고를 수 있다.</p>
</li>
</ul>
</li>
<li><p>에디터가 편하다.</p>
<ul>
<li><p>노션처럼 작성 중인 마크다운이 실시간으로 렌더링되어 보여진다. <em>(WYSIWYG 방식)</em></p>
<ul>
<li>기존에는 프리뷰를 눌러야 확인 가능한 방식이었다고 하는데, 최근 개선이 이뤄진 것으로 보인다.</li>
</ul>
</li>
<li><p>Velog의 경우 에디터 화면이 좌우로 나뉘어져 있고, 왼쪽에 마크다운을 작성하면 미리보기가 오른쪽에 반영되는 형식이다.</p>
<ul>
<li>이게 스크롤이 왼쪽 오른쪽 따로라서 은근 불편하다.</li>
</ul>
</li>
<li><p>슬래시 <em>(/)</em> 를 입력해 명령을 사용하는 것도 가능하다.</p>
</li>
<li><p>필요 시 Raw 마크다운 에디터로 전환할 수 있다.</p>
</li>
</ul>
</li>
<li><p>Github에 글을 자동으로 백업해 준다.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699739785283/04a7efe0-2bfe-4850-83f2-daee4600e201.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>상세한 통계 정보를 제공해 준다.</p>
<ul>
<li><p>Velog는 날짜별 조회수 정도만 집계해 준다.</p>
</li>
<li><p>Hashnode는 조회수, 방문자 수, 방문 시간, 방문한 페이지, 유입 경로, 브라우저, 운영체제, 접속 국가 등 훨씬 다양한 정보를 집계해 준다.</p>
</li>
</ul>
</li>
<li><p>커스텀 도메인을 지원한다.</p>
</li>
<li><p>AI를 지원한다. <em>(유료 기능)</em></p>
<ul>
<li><p>노션 AI처럼 글쓰기를 보조하는 AI가 존재한다. 아직까진 한국어 환경에서 그렇게 잘 작동하는 것 같진 않지만, 확실히 없는 것보단 낫다.</p>
</li>
<li><p>글 작성 시 전체적인 틀을 잡을 때 유용한 것 같다.</p>
</li>
</ul>
</li>
</ul>
<p>이외에도 더 많은 장점이 있겠지만, 일단은 알고 있는 장점에 대해서만 적었다. <em>(만약 추가하고 싶은 내용이 있다면, 댓글 남겨 주시면 반영하도록 하겠다.)</em></p>
<h1 id="heading-hashnode-2">Hashnode의 단점</h1>
<p>물론 Hashnode에 장점만 있는 건 아니다. 눈에 띄는 단점들도 꽤 있었다.</p>
<h2 id="heading-7jwiioyyioybmoulpc4">안 예쁘다.</h2>
<p>아니, 방금 장점에서 예쁘다고 해 놓고 이게 무슨 소리인가 싶을 수 있다.</p>
<p><strong>근데 진짜 다크 테마가 안 예쁘다.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699741055467/36554192-051c-4603-ba5e-f4d4521fdf8c.png" alt class="image--center mx-auto" /></p>
<p>기본 제공되는 다크 테마가 미드나이트 블루? 약간 심하게 푸르딩딩한 검은색이다.</p>
<p>나는 이게 너무 마음에 안 들어서 다시 Velog로 넘어가야 하나 몇 번이고 고민했지만, 결국 눈물을 머금고 직접 커스텀 CSS를 작성해서 해결했다. <em>(사용한 커스텀 CSS는 다음 포스팅에 작성하도록 하겠다.)</em></p>
<p>라이트 테마도 약간 푸르딩딩한 색이 나오긴 하는데, 다크 테마에 비하면 그렇게 이상할 정도는 아니라서 그냥 둬도 될 것 같다. <em>(나는 이것도 같이 수정하긴 했다.)</em></p>
<h2 id="heading-6rws66y4ioqwleyhscdquldriqxsnbqg67me6rwq7kcbiou5ioyvve2vmoulpc4">구문 강조 기능이 비교적 빈약하다.</h2>
<p>물론 미디엄처럼 구문 강조를 하나도 안 해 주는 것은 아니나, Velog에 비하면 빈약하다고 느껴진다.</p>
<pre><code class="lang-cpp">xil::unique_process process;

NTSTATUS status = ::PsLookupProcessByProcessId(kTargetProcessId, &amp;process);

<span class="hljs-keyword">if</span> (!NT_SUCCESS(status))
{
    LOG(ERROR, <span class="hljs-string">"PsLookupProcessByProcessId failed. (%08X)"</span>, status);

    <span class="hljs-keyword">return</span> status;
}
</code></pre>
<p>이런 느낌이다.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699752699386/bcd0ba78-f953-4524-85ef-af1f47f76348.png" alt class="image--center mx-auto" /></p>
<p>참고로 Velog는 이런 느낌이다.</p>
<p>가장 눈에 띄는 차이는, 함수 호출 부분에 하이라이팅을 해 주지 않는다. 이외에도 자잘한 차이들이 꽤 있는데, 구문 강조 기능은 아무래도 Velog의 것이 더 마음에 들었다.</p>
<p>또한 별도의 커스텀 CSS가 없을 경우, 라이트 테마에서 코드 블록만 검은 배경인 것이 약간 신경 쓰인다.</p>
<p>개인적인 생각이지만, 아무래도 이 부분은 다른 사용자들 사이에서도 꽤 요구가 있는 상황인 것 같아 조만간 개선되지 않을까 싶다.</p>
<h2 id="heading-7j2867aaiounio2broulpoyatoydtcdsojzrjidrozwg7kcb7jqp65cy7keaioyviuukloulpc4">일부 마크다운이 제대로 적용되지 않는다.</h2>
<p>예를 들어 마크다운으로 테이블을 작성할 때, 콜론 <em>(:)</em> 기호를 사용해서 좌/우/중앙 정렬을 선택할 수 있는데, 이게 Hashnode에선 무조건 왼쪽 정렬로 고정이다.</p>
<p>또 볼드/이탤릭/취소선 처리를 할 때 앞뒤로 공백이 없으면 제대로 적용이 안 될 때가 있다. asdf**asdf**asdf, asdf_asdf_asdf, asdf<s>asdf</s>asdf 이런 느낌.</p>
<p>아마 이 부분도 빠른 시일 내로 개선되지 않을까... 기대하고 있다.</p>
<h2 id="heading-7ywm66ei6rcaioylnoykpo2fncdshktsojxsnyqg65sw65286rca7keaioyviuukloulpc4">테마가 시스템 설정을 따라가지 않는다.</h2>
<p>라이트 테마와 다크 테마를 지원하고, 어떤 테마를 기본으로 사용할지도 지정할 수 있지만, 아쉽게도 시스템 설정을 따라가도록 하는 기능은 아직 없는 것 같다.</p>
<p>Velog는 기본적으로 시스템 설정을 따라가도록 되어 있고, 필요할 시 둘 중 하나를 직접 선택할 수 있도록 되어 있다. 그러나 Hashnode에는 이와 같은 기능이 없어 아쉬웠다.</p>
<h2 id="heading-httpshashnodecomprivacy"><a target="_blank" href="https://hashnode.com/privacy">개인정보 처리방침</a>이 마음에 안 든다.</h2>
<p>사실 이거 읽어보는 사람이 있을까 싶긴 하지만, 나는 그래도 되도록이면 항상 읽으려고 노력하는 편이다.</p>
<p>Hashnode 개인정보 처리방침을 읽으면서 마음에 안 들었던 부분은 아래와 같다.</p>
<blockquote>
<h3 id="heading-3-information-we-collect-through-automatic-data-collection-technologies">3. Information We Collect Through Automatic Data Collection Technologies:</h3>
<p>(중략)</p>
<p>As you navigate through and interact with the Websites and/or the Service, we may use automatic data collection technologies to collect certain information about your equipment, browsing actions, and patterns, including:</p>
<ul>
<li>Details of your visits to the Websites and the Service, including traffic data, location data, logs, and other communication data and the resources that you access and use on the Websites and Service.</li>
</ul>
</blockquote>
<p>자동 수집 항목에 위치 데이터가 있다. 물론 이게 GPS 데이터처럼 정밀한 위치 정보를 의미하는 것 같지는 않고, 접속 IP나 언어 설정을 기반으로 한 국가 정보 정도인 것으로 추측된다. <em>(블로그 통계에서 보여주는 내용 중에도 방문자의 국가 정보가 있다.)</em></p>
<blockquote>
<h3 id="heading-5-disclosure-of-your-information">5. Disclosure of Your Information:</h3>
<p>We may disclose aggregated information about our users, and information that does not identify any individual, without restriction.</p>
<p>We may disclose personal information that we collect or you provide as described in this privacy policy:</p>
<ul>
<li>To our subsidiaries and affiliates.</li>
</ul>
<p>(중략)</p>
<ul>
<li>To third parties (collectively, the "Third Party Vendors") to further the purpose for which you provided such information to us. For example, we may share your information our email platform, for the purpose of sending emails or with other vendors for the purposes of payment processing, delivery of goods, search engine facilities, advertising and marketing.</li>
</ul>
</blockquote>
<p>수집한 개인정보가 공개되는 범위도 약간 찜찜하다.</p>
<ul>
<li><p>자회사 및 계열사에 공개할 수 있다.</p>
</li>
<li><p>제3자에게 개인정보를 제공할 수 있다.</p>
<ul>
<li><p>정확히 어떤 제3자에게 어떤 정보를 제공하는지 명시되어 있지 않다.</p>
</li>
<li><p>제공 목적에 광고 및 마케팅 목적이 포함되어 있다.</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<h3 id="heading-13-opt-out-process">13. Opt-Out Process:</h3>
<p>(중략)</p>
<p>However, we are not responsible for, and in some cases we are incapable of, removing your personally identifiable information from the lists of any third party who has previously been provided your information in accordance with this Privacy Policy or your consent. You should contact such third parties directly.</p>
</blockquote>
<p>이미 이전에 제3자에게 제공된 개인정보의 경우 삭제할 책임이 없으니 필요하면 직접 연락해서 삭제하라고 한다. 근데 그러려면 적어도 그 제3자가 누구인지 정도는 알려줘야 하는 것 아닌가...?</p>
<blockquote>
<h3 id="heading-17-servers">17. Servers:</h3>
<p>Our servers are maintained in the United States. By using the Service, you freely and specifically give us your consent to export your personally identifiable information to the United States and to store and use it in the United States as specified in this Privacy Policy. You understand that data stored in the United States may be subject to lawful requests by the courts or law enforcement authorities in the United States.</p>
</blockquote>
<p>서버가 미국에 있고 데이터가 미국 법원 또는 법 집행 기관의 합법적인 요청의 대상이 될 수 있다고 한다.</p>
<p>근데 사실 구글 본사도 미국에 있으니... 본인이 범죄 행위에 연루된 게 아닌 이상 크게 신경 안 써도 될 것 같다. <em>(근데 범죄자가 기술 블로그를 쓸 일이 있나...?)</em></p>
<h2 id="heading-66gc6re47j24iou5houwgouyio2yuoqwgcdsl4bri6qu">로그인 비밀번호가 없다.</h2>
<p>로그인 비밀번호가 없는 대신 로그인 이메일을 보내주는 방식이다.</p>
<p>사실 Velog에서 Hashnode로 넘어온 이유 중에 하나가 Velog가 로그인할 때마다 로그인 이메일을 보내주는 게 불편해서였는데, 막상 와 보니 Hashnode도 동일한 방식이어서 꽤나 실망했다...</p>
<p>어쩌면 나만 모르는 유행인 걸지도 모르겠다.</p>
<p>만약 이 방식을 더 선호하는 사람이 있다면, 오히려 장점이라고도 볼 수 있을 것 같다.</p>
<h2 id="heading-css">커스텀 CSS의 적용 범위가 제한적이다.</h2>
<p>에디터 화면이나 미리보기 화면에선 적용되지 않는다.</p>
<p>현재로선 <a target="_blank" href="https://chrome.google.com/webstore/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne">Stylus</a> 등 별도 브라우저 확장을 이용하는 방법밖엔 없는 듯하다.</p>
<h1 id="heading-66ei7lmy66mw">마치며</h1>
<p>이상으로 내가 Velog에서 Hashnode로 이주한 이유, Hashnode의 장점과 단점 등에 대해 다뤄 보았다.</p>
<p>뭔가 모아두고 보니 단점이 엄청나게 많은 느낌이 돼버렸으나... 실제로는 그렇지 않다. 장점이 단점을 모두 덮을 만큼 충분히 매력적인 서비스이다.</p>
<p>사실 나는 개인정보 처리방침으로 인해 가입을 정말 많이 망설였으나, 막상 따지고 보면 가입 시 입력하는 정보가 이메일 말곤 뭐가 딱히 없다. 나처럼 개인정보 보호에 병적으로 집착하는 게 아닌 이상 전혀 신경 안 써도 될 문제 같다.</p>
<p>나머지 단점들도 대부분 이미 커스텀 CSS 등 대안이 존재하거나, 추후 업데이트를 통해 계속해서 개선이 진행될 사항으로 보인다.</p>
<p>앞으로도 계속 발전할 것으로 기대되는 서비스인 만큼, 더 많은 사람들에게 알려지고, 더 많은 사람들이 이용하는 플랫폼이 되기를 기대한다. <em>(근데 또 너무 많이는 말고...)</em></p>
<p>이 글이 기술 블로그 플랫폼을 고민하던 누군가에게 도움이 되었기를 바란다.</p>
]]></content:encoded></item></channel></rss>