www.git

www

~ Personal site — projects, posts, about. Built with sqzass.
git clone https://github.com/debuman/www.git
commit 42e8483ffe3c6bc0558b783432f5cf6942bc2d4c
parent 33bf676e4aa49ca3add0a290ce68fc197a8aa2cb
Author: sqzer <110329244+sqzer-x@users.noreply.github.com>
Date: Tue, 4 Aug 2026 14:48:03 +0900

Finish the gallery: lattice, per-project accents, tooltips

Closes the rest of the review that the first pass left open.

The feature grid gets its hairlines back. Rebuilding the surface dropped the
overlapped-1px lattice, and the track floor was low enough that 71rem gave four
columns — so six features rendered as four plus two, with the last row's empty
cells drawn as a half-finished table. A 20rem floor gives three columns, and six
features fill two rows exactly. Cells raise their z-index on hover, or the
neighbour's border wins and only two sides light.

Each project now sets its own accent on the article root, so the eyebrow dash,
the feature numerals, the links and the focus ring all follow it. The values sit
in one narrow band — mid lightness, low saturation — because the point is that a
project has a tint, not that it has a colour scheme. A project with no accent
gets no inline style and falls back to the site's.

Brief pages drop a step of title scale and lose the hero's closing rule. The
tiers differed only by a hidden column before, which reads as the same page
truncated rather than a different kind of page.

Icon-only links get drawn tooltips. The native title attribute arrives about a
second late in a shape that belongs to the browser, not the site; aria-label
already carries the accessible name, so this is only the visible half.

Also removed four rule sets the rewrite orphaned — a stylesheet where you cannot
tell what is still load-bearing is worse than a slightly longer one.

Diffstat:
Mcontent/projects/doomsday.ko.md | 1+
Mcontent/projects/doomsday.md | 1+
Mcontent/projects/ommp.ko.md | 1+
Mcontent/projects/ommp.md | 1+
Mcontent/projects/sqzass.ko.md | 1+
Mcontent/projects/sqzass.md | 1+
Mcontent/projects/uaf.ko.md | 1+
Mcontent/projects/uaf.md | 1+
Mcontent/projects/udfx.ko.md | 1+
Mcontent/projects/udfx.md | 1+
Mcontent/projects/usfx.ko.md | 1+
Mcontent/projects/usfx.md | 1+
Mstatic/css/main.css | 61+++++++++++++++++++++++++++++++++++++++++++++----------------
Mtemplates/project.html | 3++-
Mtemplates/projects.html | 8++++----
15 files changed, 63 insertion(+), 21 deletion(-)

diff --git a/content/projects/doomsday.ko.md b/content/projects/doomsday.ko.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "GNOME 45 · 46 · 47"
 repo     = "https://github.com/sqzer-x/doomsday"
 stars     = 0
+accent     = "#c98a8a"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/doomsday.md b/content/projects/doomsday.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "GNOME 45 · 46 · 47"
 repo     = "https://github.com/sqzer-x/doomsday"
 stars     = 0
+accent     = "#c98a8a"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/ommp.ko.md b/content/projects/ommp.ko.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "Linux"
 repo     = "https://github.com/sqzer-x/ommp"
 stars     = 0
+accent     = "#7fc0d4"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/ommp.md b/content/projects/ommp.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "Linux"
 repo     = "https://github.com/sqzer-x/ommp"
 stars     = 0
+accent     = "#7fc0d4"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/sqzass.ko.md b/content/projects/sqzass.ko.md
@@ -15,6 +15,7 @@ version  = "0.1.0"
 platform = "Linux · macOS"
 repo     = "https://github.com/sqzer-x/sqzass"
 stars     = 0
+accent     = "#e0a06a"
 mark     = "images/projects/sqzass.png"
 logo     = ""
 
diff --git a/content/projects/sqzass.md b/content/projects/sqzass.md
@@ -15,6 +15,7 @@ version  = "0.1.0"
 platform = "Linux · macOS"
 repo     = "https://github.com/sqzer-x/sqzass"
 stars     = 0
+accent     = "#e0a06a"
 mark     = "images/projects/sqzass.png"
 logo     = ""
 
diff --git a/content/projects/uaf.ko.md b/content/projects/uaf.ko.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "Linux"
 repo     = "https://github.com/sqzer-x/uaf"
 stars     = 0
+accent     = "#9aa6cc"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/uaf.md b/content/projects/uaf.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "Linux"
 repo     = "https://github.com/sqzer-x/uaf"
 stars     = 0
+accent     = "#9aa6cc"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/udfx.ko.md b/content/projects/udfx.ko.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "Windows"
 repo     = "https://github.com/sqzer-x/udfx"
 stars     = 0
+accent     = "#c2a06e"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/udfx.md b/content/projects/udfx.md
@@ -15,6 +15,7 @@ version  = ""
 platform = "Windows"
 repo     = "https://github.com/sqzer-x/udfx"
 stars     = 0
+accent     = "#c2a06e"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/usfx.ko.md b/content/projects/usfx.ko.md
@@ -15,6 +15,7 @@ version  = "1.2.0"
 platform = "크로스 플랫폼"
 repo     = "https://github.com/sqzer-x/usfx"
 stars     = 1
+accent     = "#8fb9a2"
 mark     = ""
 logo     = ""
 
diff --git a/content/projects/usfx.md b/content/projects/usfx.md
@@ -15,6 +15,7 @@ version  = "1.2.0"
 platform = "Cross-platform"
 repo     = "https://github.com/sqzer-x/usfx"
 stars     = 1
+accent     = "#8fb9a2"
 mark     = ""
 logo     = ""
 
diff --git a/static/css/main.css b/static/css/main.css
@@ -144,10 +144,6 @@ a { color: inherit; text-decoration: none; }
 ::-webkit-scrollbar-thumb { background: var(--rule-2); border-radius: 999px; }
 ::-webkit-scrollbar-thumb:hover { background: var(--ink-4); }
 
-.sr-only {
-  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
-  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
-}
 
 .skip {
   position: absolute; left: -9999px; top: 0; z-index: 100;
@@ -314,7 +310,7 @@ main { display: block; padding-bottom: clamp(5rem, 12vw, 9rem); }
   content: ""; width: clamp(1.5rem, 4vw, 2.25rem); height: 1px;
   background: var(--rule-3); flex: none;
 }
-.wing h2, .wing-label {
+.wing h2 {
   margin: 0;
   font-size: clamp(1.35rem, 1.15rem + 0.9vw, 1.7rem);
   font-weight: 300; letter-spacing: 0.02em; line-height: 1.2;
@@ -325,14 +321,6 @@ main { display: block; padding-bottom: clamp(5rem, 12vw, 9rem); }
   font-size: 0.92rem; color: var(--ink-3);
 }
 
-/* 더 작은 머리 — Archived 처럼 갈래 안의 갈래. */
-.wing-minor {
-  margin: clamp(3rem, 7vw, 4.5rem) 0 clamp(1.25rem, 3vw, 1.75rem);
-  text-align: center;
-  font-size: 0.7rem; font-weight: 400;
-  letter-spacing: 0.22em; text-transform: uppercase;
-  color: var(--ink-4);
-}
 
 /* ---------- home hero ---------- */
 
@@ -549,6 +537,26 @@ main { display: block; padding-bottom: clamp(5rem, 12vw, 9rem); }
 }
 .tile-links a:hover, .frame-meta a:hover { color: var(--accent); transform: translateY(-2px); }
 
+/* 아이콘만 있는 링크에는 이름이 안 보인다. title 속성은 브라우저가 1초쯤 뒤에
+   자기 모양으로 띄우는데, 그 지연과 모양이 사이트와 무관하다. 같은 값을
+   data-tooltip 으로도 주고 우리가 그린다. aria-label 이 접근성을 이미 책임지므로
+   이건 순수하게 눈에 보이는 쪽이고, 그래서 aria-hidden 이다. */
+[data-tooltip] { position: relative; }
+[data-tooltip]::after {
+  content: attr(data-tooltip);
+  position: absolute; bottom: calc(100% + 0.5rem); left: 50%;
+  transform: translateX(-50%) translateY(0.2rem);
+  padding: 0.28rem 0.5rem; white-space: nowrap; pointer-events: none;
+  background: var(--bg-3); color: var(--ink-2);
+  border: 1px solid var(--rule-2); border-radius: var(--radius);
+  font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase;
+  opacity: 0; transition: opacity var(--tr-ink), transform var(--tr-ink);
+}
+[data-tooltip]:hover::after, [data-tooltip]:focus-visible::after {
+  opacity: 1; transform: translateX(-50%) translateY(0);
+}
+html[lang="ko"] [data-tooltip]::after { letter-spacing: 0; text-transform: none; }
+
 /* 타일 전체가 상세 페이지로 가는 링크. 아이콘만 위로 올린다. */
 .tile-link::after { content: ""; position: absolute; inset: 0; }
 
@@ -656,8 +664,18 @@ main { display: block; padding-bottom: clamp(5rem, 12vw, 9rem); }
 
 /* ---------- project detail ---------- */
 
+/* 프로젝트마다 자기 색조를 갖는다. 전역 --accent 를 이 페이지 안에서만
+   덮으므로 eyebrow 대시·특징 번호·링크·포커스가 한꺼번에 따라간다. 값이 없는
+   프로젝트는 인라인 style 이 아예 안 붙어서 사이트 기본값을 쓴다.
+   대비 범위는 좁게 잡는다 — 중간 명도, 낮은 채도. 니어블랙 위에서 읽히면서도
+   페이지를 자기 색으로 물들이지는 않는 띠다. */
 .project { padding-bottom: clamp(3rem, 8vw, 6rem); }
 
+/* 브리프는 읽는 폭 안에 살고 제목도 한 단계 작다. 등급 차이가 열 개수가
+   아니라 타이포로 보여야 한다 — 그러지 않으면 "같은 페이지, 더 짧은 것"이다. */
+.project[data-tier="brief"] .hero-name { font-size: clamp(2rem, 1.6rem + 1.6vw, 2.8rem); }
+.project[data-tier="brief"] .hero { border-bottom: 0; padding-bottom: clamp(1.5rem, 3vw, 2rem); }
+
 .hero {
   display: grid; grid-template-columns: 1.35fr 1fr;
   gap: clamp(1.5rem, 5vw, 4rem); align-items: center;
@@ -751,12 +769,25 @@ main { display: block; padding-bottom: clamp(5rem, 12vw, 9rem); }
 }
 .block-intro { margin: 0.8rem auto 0; max-width: 56ch; color: var(--ink-3); }
 
-.lattice { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
+/* 선은 음수 마진으로 겹친 1px 이다. 개수와 열수가 무엇이든 맞아 들어가고
+   :nth-child 규칙이 필요 없다. 20rem 은 임의값이 아니다 — 71rem 안에서 열이
+   3개가 되고, 특징을 여섯 개로 쓰면 두 줄이 정확히 찬다. */
+.lattice {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
+  border-top: 1px solid var(--rule);
+  border-left: 1px solid var(--rule);
+}
 .cell {
   position: relative; isolation: isolate;
   padding: clamp(1.25rem, 3vw, 1.75rem) clamp(1rem, 2vw, 1.5rem);
   min-width: 0;
+  margin: 0 -1px -1px 0;
+  border-right: 1px solid var(--rule);
+  border-bottom: 1px solid var(--rule);
 }
+/* hover 에서 위로 올린다. 그러지 않으면 이웃에 가려 두 변만 밝아진다. */
+.cell:hover { z-index: 1; border-color: var(--rule-2); }
 .cell::before {
   content: ""; position: absolute; inset: 0; z-index: -1;
   background: radial-gradient(closest-side, rgba(var(--glow), 0.045), transparent 72%);
@@ -772,8 +803,6 @@ main { display: block; padding-bottom: clamp(5rem, 12vw, 9rem); }
 .cell:hover .cell-index { color: var(--accent); }
 .cell-title { margin: 0; font-size: 1rem; font-weight: 400; letter-spacing: 0.012em; }
 .cell-desc { margin: 0.5rem 0 0; font-size: 0.86rem; color: var(--ink-3); text-wrap: pretty; }
-.cell-link { display: block; }
-.cell-link:hover .cell-title { color: var(--accent); }
 
 /* ---------- terminal ---------- */
 
diff --git a/templates/project.html b/templates/project.html
@@ -12,7 +12,8 @@
 {% from "partials/icons.html" import i_out, i_arrow %}
 
 {% block content %}
-<div class="{{ "wrap" if page.extra.tier == "landing" else "wrap wrap-read" }} project" data-tier="{{ page.extra.tier }}">
+<div class="{{ "wrap" if page.extra.tier == "landing" else "wrap wrap-read" }} project" data-tier="{{ page.extra.tier }}"
+     {%- if page.extra.accent %} style="--accent: {{ page.extra.accent }}"{% endif %}>
 
   {%- if page.section %}
   <a class="back" href="{{ page.section.url }}">
diff --git a/templates/projects.html b/templates/projects.html
@@ -50,10 +50,10 @@
         <span class="lang stars">{{ p.stars }} ★</span>
         {%- endif %}
         {%- if p.site %}
-        <a href="{{ p.site }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("website") }}">{{ i_site() }}</a>
+        <a href="{{ p.site }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("website") }}" data-tooltip="{{ t("website") }}">{{ i_site() }}</a>
         {%- endif %}
         {%- if p.repo %}
-        <a href="{{ p.repo }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("source") }}">{{ i_repo() }}</a>
+        <a href="{{ p.repo }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("source") }}" data-tooltip="{{ t("source") }}">{{ i_repo() }}</a>
         {%- endif %}
       </div>
     </article>
@@ -86,10 +86,10 @@
         </p>
         <p class="tile-links">
           {%- if p.site %}
-          <a href="{{ p.site }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("website") }}">{{ i_site() }}</a>
+          <a href="{{ p.site }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("website") }}" data-tooltip="{{ t("website") }}">{{ i_site() }}</a>
           {%- endif %}
           {%- if p.repo %}
-          <a href="{{ p.repo }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("source") }}">{{ i_repo() }}</a>
+          <a href="{{ p.repo }}" target="_blank" rel="noopener noreferrer" aria-label="{{ p.name }} — {{ t("source") }}" data-tooltip="{{ t("source") }}">{{ i_repo() }}</a>
           {%- endif %}
         </p>
       </article>