<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><id>https://oni.sqzer.com/www/atom.xml</id><title>www</title><subtitle>Personal site — projects, posts, about. Built with sqzass.</subtitle><link rel="self" href="https://oni.sqzer.com/www/atom.xml"/><updated>2026-08-26T04:56:47Z</updated><entry><id>urn:git:3e605aa16841afe6f4509ad55ddb72dd21701284</id><title>Refresh star counts</title><published>2026-08-26T04:56:47Z</published><updated>2026-08-26T04:56:47Z</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/3e605aa16841afe6f4509ad55ddb72dd21701284.html"/><content type="text">Refresh star counts
</content></entry>
<entry><id>urn:git:66d2196fec1bf95eeff1414aa7da30fc29eed53a</id><title>Refresh star counts</title><published>2026-08-20T04:54:25Z</published><updated>2026-08-20T04:54:25Z</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/66d2196fec1bf95eeff1414aa7da30fc29eed53a.html"/><content type="text">Refresh star counts
</content></entry>
<entry><id>urn:git:fb2de22dfc2d82a52a8359f494d49667a8b7253f</id><title>Refresh star counts</title><published>2026-08-19T04:52:46Z</published><updated>2026-08-19T04:52:46Z</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/fb2de22dfc2d82a52a8359f494d49667a8b7253f.html"/><content type="text">Refresh star counts
</content></entry>
<entry><id>urn:git:688cc0233af003429d75ff6729292267ed23c4db</id><title>Refresh star counts</title><published>2026-08-18T04:53:21Z</published><updated>2026-08-18T04:53:21Z</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/688cc0233af003429d75ff6729292267ed23c4db.html"/><content type="text">Refresh star counts
</content></entry>
<entry><id>urn:git:c99c92e3635608c376693ea3bed55cd49429411f</id><title>Align the stars line with the repo line above it</title><published>2026-08-06T20:03:46+09:00</published><updated>2026-08-06T20:03:46+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/c99c92e3635608c376693ea3bed55cd49429411f.html"/><content type="text">Align the stars line with the repo line above it

stars.py copies the repo line&#39;s padding onto the line it writes, and &quot;stars&quot; is
one character longer than &quot;repo&quot;, so every equals sign it wrote sat one column
right of the one above it. Both catalogues are hand-aligned TOML, so the tool was
undoing by hand what the files do by convention — and doing it again on every
daily run.
</content></entry>
<entry><id>urn:git:2ec115cd8acb54f164e17089f99761be8722393f</id><title>Add a worklog</title><published>2026-08-06T20:02:15+09:00</published><updated>2026-08-06T20:02:15+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/2ec115cd8acb54f164e17089f99761be8722393f.html"/><content type="text">Add a worklog

Commit messages carry the reasoning for each change, so the worklog carries what
they cannot: where a decision was reversed, where the same mistake recurred, and
what is still open.

Three things it records that would otherwise be lost. The reference site&#39;s
relationship changed three times and the current rule is neither &quot;copy it&quot; nor
&quot;avoid it&quot; — it is fix what measures worse. Two decisions were reversed, the
project page rewrite and the desaturation filter, and the second came back for a
different reason than it left. And the same fault was written three times, in the
card title, the rail label and the mosaic tiles: a box sized against one thing
and its text against another, which always clips somewhere and clips silently
when overflow is hidden.

It also records two checks that reported the wrong answer — scrollHeight against
a centred flex column, and exists() against a directory with no index — because
both let a real defect ship while looking green.
</content></entry>
<entry><id>urn:git:f51b9910f0fbc511cc5a73008dcba4b5ec37629e</id><title>Refresh star counts</title><published>2026-08-06T06:46:52Z</published><updated>2026-08-06T06:46:52Z</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/f51b9910f0fbc511cc5a73008dcba4b5ec37629e.html"/><content type="text">Refresh star counts
</content></entry>
<entry><id>urn:git:b41f01ac14e1b3349d9b3f5da4f3a2383fae1ae0</id><title>Smaller type in the section heads and the mosaic tiles</title><published>2026-08-05T20:12:45+09:00</published><updated>2026-08-05T20:12:45+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/b41f01ac14e1b3349d9b3f5da4f3a2383fae1ae0.html"/><content type="text">Smaller type in the section heads and the mosaic tiles

Writing and Projects go from 32.3px to 24.7. The tile names go from 24.5 to
20 on the small tiles and 33 to 25.7 on the large one, and the line under each
from 16.7 to 15.2.

Shrinking them surfaced the same fault the card had, one band lower: between
740 and 1000px the small tiles hold their 2.1:1 ratio while their text does not
shrink as fast, so the text ran past the bottom of a box that has overflow
hidden. Below 72rem the small tiles stop holding a ratio and take the height
their text asks for; the large one spans them and follows. A picture is a thing
that crops, and text is not, so where they disagree the text should win.

Swept 1920 down to 420: no tile overflows at any width now.
</content></entry>
<entry><id>urn:git:18d578a3b11bbd6ba0f4fac751a3156a64cf7d99</id><title>Star counts on the mosaic, and colour only where the hand is</title><published>2026-08-05T20:03:45+09:00</published><updated>2026-08-05T20:03:45+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/18d578a3b11bbd6ba0f4fac751a3156a64cf7d99.html"/><content type="text">Star counts on the mosaic, and colour only where the hand is

Two details from the reference I had left out.

Every tile carries its star count, zero included. The number lives in the home&#39;s
catalogue beside the picture, which means it would have gone stale the moment
the real one changed: stars.py only walked content/projects. It walks all of
content now, so any repo-and-stars pair anywhere gets refreshed on the daily run,
and its report names files by path rather than by basename since there is more
than one directory in scope.

The pictures are desaturated at rest and come back to full colour under the
cursor. That is the reference&#39;s device, and it is also the first line of this
stylesheet: colour is absent at rest and appears where a hand is. Applying it to
the pictures rather than only to links is the same sentence carried further. It
stays inside the rule that hover changes colour and nothing else — nothing
moves, nothing scales, and it runs on the sheet&#39;s single duration.

I removed exactly this filter once before, when it was a value copied from the
reference with nothing behind it. It comes back with a reason this time, which
is a different thing, and the note in the sheet says so rather than pretending
the earlier decision never happened.
</content></entry>
<entry><id>urn:git:a65e87750477cfeb53389d642bc2e9ce7c59d830</id><title>The project section becomes a mosaic</title><published>2026-08-05T19:40:01+09:00</published><updated>2026-08-05T19:40:01+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/a65e87750477cfeb53389d642bc2e9ce7c59d830.html"/><content type="text">The project section becomes a mosaic

Four tiles instead of six in a symmetric grid: one large on the left, three
stacked beside it. A 3x2 of equal boxes says all six carry the same weight, and
a section has something it wants to put first. The rest are what the door is for.

Every tile is a picture with the name and the line about it sitting on a band at
the bottom, the way the reference does it. Where a picture exists it fills the
tile: ommp has a cover, sqzass has its mark and it sits on the project&#39;s own
colour. Where none exists the colour stands alone — every project already has a
colour chosen for its own page, and that colour says more about the project than
a plaque reading &quot;no image&quot; does. A cover arriving later is one line in the
catalogue.

The band under the text goes solid before it reaches the type rather than
fading through it. Fading through it is how a light title ends up on a light
picture, which is exactly what ommp&#39;s cover did on the first attempt.

Pictures and colours live in a catalogue on the home page because listings carry
no extra, but only the pictures, the colours and the order live there — the name
and the description still come from the listing, so the two cannot drift.
tools/check.py verifies each URL names a real project and that every file named
exists, and I proved it fails by pointing one at a project that is not there.

Worth saying plainly: this is the reference&#39;s structure, not the reference&#39;s
look, and the distance between them is six paintings. Two of our six projects
have artwork. The other four are honest colour fields, and they read better in
the dark theme than the light one.
</content></entry>
<entry><id>urn:git:8322b7bb6cc6b3880a8c651e6a3b75a23f1a424c</id><title>The card&#39;s type follows the card, not the window</title><published>2026-08-05T19:34:53+09:00</published><updated>2026-08-05T19:34:53+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/8322b7bb6cc6b3880a8c651e6a3b75a23f1a424c.html"/><content type="text">The card&#39;s type follows the card, not the window

The clipping was still there below about 950px and I had measured the wrong
thing to conclude otherwise: I asked whether the label scrolled, and a flex
column centred on its axis does not report overflow that leaves through the top.
Rendering it at five widths and looking showed it immediately — at 920 the g in
&quot;Beginning&quot; loses its tail and the second line of the description is cut in half.

The cause is that the box and the text were sized against different things. The
card&#39;s width comes from its container and shrinks quickly; the title&#39;s came from
a vw term and shrank slowly. Below about 950 the text stopped fitting in a box
that was still getting smaller, and overflow: hidden did the rest.

Both are on the same number now. The card is a container and its title, its
description, its padding and its gaps are all in cqw, so the text scales with the
box that holds it and cannot outrun it. Measured across 1920 to 900: 39 to 63px
of clearance above and below the text at every width, no clipping anywhere, and
the title stays on one line throughout rather than jumping to two partway down.

The card is also smaller. Its section now stops at 58rem rather than 71 — 1102px
against 1235 — so at a maximised window the card is 1102 x 413 instead of
1235 x 463, and the section head, the card and the project grid all begin and
end on the same two verticals.
</content></entry>
<entry><id>urn:git:b6014e325abd22f4985243743cd58e333fda5a48</id><title>Fold two comments that both began &quot;두 줄까지&quot;</title><published>2026-08-05T19:15:36+09:00</published><updated>2026-08-05T19:15:36+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/b6014e325abd22f4985243743cd58e333fda5a48.html"/><content type="text">Fold two comments that both began &quot;두 줄까지&quot;

The rail label ended up with the old note about the row floor and the new one
about the clamp stacked on top of each other, both opening the same way. One
note, one reason each.
</content></entry>
<entry><id>urn:git:02c814e71aa26c7b9f999397a81a59c9394c2016</id><title>The reading rail had the same broken clamp</title><published>2026-08-05T19:14:44+09:00</published><updated>2026-08-05T19:14:44+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/02c814e71aa26c7b9f999397a81a59c9394c2016.html"/><content type="text">The reading rail had the same broken clamp

Same construction as the card title, same engine, so the same outcome: display
computes to flow-root, -webkit-line-clamp does nothing, and overflow: hidden
cuts the line box at line-height. At 1.35 against a 1.44em line box that is
about a pixel off each label — small, and wrong for the same reason.

max-height counts the lines and padding-bottom holds the descender, as on the
card. No -webkit-line-clamp is left in the stylesheet.

Verified by rendering it rather than by reading it: no post currently has
headings, so the rail does not build at all. I put two headings into the post
temporarily, one long enough to wrap, and measured all three labels — the run
sits inside the box on every one. The headings are removed again; the post is
byte-for-byte what it was.
</content></entry>
<entry><id>urn:git:514a56600e17ba903261ddd2b23015c4fd6f486d</id><title>Tiles become cards, the newest post moves above its section head, and a descender stops being cut</title><published>2026-08-05T19:01:20+09:00</published><updated>2026-08-05T19:01:20+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/514a56600e17ba903261ddd2b23015c4fd6f486d.html"/><content type="text">Tiles become cards, the newest post moves above its section head, and a
descender stops being cut

Four things.

The title was clipped. I had reached for -webkit-line-clamp to cap the title at
three lines in a fixed-height card, and in this engine that combination computes
display as flow-root, which kills the clamp and leaves overflow: hidden behind.
The box is then line-height tall, 1.2em, while the text&#39;s own line box is
1.44em, so six pixels came off the bottom — the descender of the g in
&quot;Beginning&quot;. Line count is counted with max-height now and padding-bottom gives
the descender somewhere to sit. Both in em, so they follow the size. Measured:
the run&#39;s bottom now sits 7px inside the box instead of 6px outside it. The
description had the same construction and keeps its two-line cap the same way,
though its 1.65 line-height was already loose enough to have hidden the bug.

The newest post moves above the section head. That one piece is not an entry in
the list, it is what is being put out now; the head belongs to the list that
follows it. Underneath, the ledger caps at three rows and everything past that
is what the All posts door is for. With one post written the list renders empty,
which is the honest state and not a hole to fill.

The section&#39;s top space moves with it. It used to be carried by the head&#39;s
margin, and the head is no longer the first thing in the section, so the card
carries it and the head keeps a smaller one — the distance between two sections
and the distance inside one should not be the same number.

The project tiles get a border, a ground and a left edge. They were the only
things on the page with no frame at all, so a single card floated at the top
while everything below it was loose type, and they were centred under a head
that starts at the left. The facts line pins to the bottom of each card with
margin-top: auto, so a row of them agrees on where that line sits however long
the blurbs run.
</content></entry>
<entry><id>urn:git:5e191b0b5ee3ac0cda2d06c49309a85629077be1</id><title>One size for every post, and a section head that is one line</title><published>2026-08-05T18:47:11+09:00</published><updated>2026-08-05T18:47:11+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/5e191b0b5ee3ac0cda2d06c49309a85629077be1.html"/><content type="text">One size for every post, and a section head that is one line

The card no longer changes size with the post in it. Its height came from
whichever was taller, the picture&#39;s ratio or the label&#39;s text, so a long title
grew the box. The ratio now sits on the card itself: 8/3, which is not a chosen
number — the picture takes 0.6 of the card&#39;s width and is 16:10, so the card is
0.6W ÷ 1.6 = W ÷ 2.667. The picture just fills its cell. The title clamps at
three lines and the description at two, which at 1440 needs 240 of the 247px the
label has spare, so nothing is cut for any title that will realistically arrive.
Swept 1920 down to 900 with titles of 15, 40 and 97 characters: 2.67:1 at every
one, no overflow.

The stacking point moves from 46rem to 56rem, because below about 900px the
fixed box cannot hold four lines and the honest answer there is to stack rather
than to bend the box.

The section head becomes one row: the name, a hairline running the width, and
the door to that section at the far end. It was a centred heading above the
content and a centred door below it, 166px of chrome around the card with the
head and the tail of one section separated by everything between them. Now it is
39px and both ends are in the same place.

Left-anchored, because everything under it already is — the card&#39;s label starts
at the left, the ledger&#39;s date gutter starts at the left. The centred axis
belongs to the hero and to a single piece of writing; a section head belongs to
the list beneath it, and it now shares that list&#39;s left edge exactly.

Project group heads on /projects/ use the same row without a door, so the
hairline runs to the end. Their note moves left to sit under the head rather
than centred beneath a left-anchored line.
</content></entry>
<entry><id>urn:git:48fd81024925279e6f7e864fee036ceb238dafce</id><title>The featured card stops being flat</title><published>2026-08-05T18:34:01+09:00</published><updated>2026-08-05T18:34:01+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/48fd81024925279e6f7e864fee036ceb238dafce.html"/><content type="text">The featured card stops being flat

Ours was 1235 x 400 = 3.09:1 against the reference&#39;s 1123 x 422 = 2.66:1. The
card was visibly flatter and that was the whole of the difference in height.

The cause: the &lt;video&gt;&#39;s width and height attributes state 16:9, and with no CSS
ratio that intrinsic figure became the grid row. So the picture&#39;s own file
decided the card&#39;s proportion. This site&#39;s picture ratio is 16:10 — the project
frames on /projects/ already use it — and this card was the one place not
following it. With aspect-ratio declared, the row is the greater of the label&#39;s
natural height and the picture&#39;s width over 1.6, so a long title still wins and
grows the card. 1235 x 464 = 2.66:1, the reference&#39;s proportion exactly.

The crop is horizontal now, which is the safe direction for this poster: the
mandala and the figure are both centred, so what leaves the frame is background.
Flat would have cropped vertically, and vertically the first thing to go is her
head.

The split moves 1.35fr to 1.5fr, near the reference&#39;s 1.55, and the title to
49.4px at 1440. That is not a size picked for effect: the label&#39;s measure is
401px there and the title now runs 396 of it. A headline that fills its column
is why the reference&#39;s card reads as a headline and ours read as a caption —
theirs runs 353 of 353. Past this size a fifteen-character title breaks in two,
which looks forced; a longer one breaks on its own and the card grows with it.

What still differs is the one thing no stylesheet reaches. Their label is 87.7%
full because their title is thirty-nine characters and wraps to three lines.
Ours is 56% full because &quot;A New Beginning&quot; is fifteen and takes one. Below
1000px ours already fills completely, because the column narrows until the title
wraps.
</content></entry>
<entry><id>urn:git:81189e7b43b4e14ac964740c70f038dfe649d39b</id><title>Three corrections to the card I just shipped</title><published>2026-08-05T18:09:56+09:00</published><updated>2026-08-05T18:09:56+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/81189e7b43b4e14ac964740c70f038dfe649d39b.html"/><content type="text">Three corrections to the card I just shipped

A review of that commit caught three things, all mine.

The comment justifying text-wrap: pretty said balance forces a title onto one
line. That is not true — measured on a 39-character title, both give three lines
and balance only evens their lengths. Every other title in this sheet is balance;
I had made an exception for a reason that does not exist, so it is balance again
and the comment now records what was actually measured.

The Read post underline went to accent on hover, in a card whose own comment two
rules above says the accent here belongs to the date and nothing else. Two
accents in one box. The underline steps one rung along the hairline ladder now.

The label&#39;s padding was capped at 3.2rem, which it reaches at 1507px — long
after the card stops growing at 1349. Between those two widths the box stood
still while its padding kept expanding. Capped at 2.4rem, so both stop together.

And one the review did not catch but the widening caused: .ledger-title had no
maximum, which was fine in a 950px reading measure and is not fine now that the
home page&#39;s writing room is 1235 and its body column runs 1080. Capped at 42ch,
the same treatment the description already had at 58ch.
</content></entry>
<entry><id>urn:git:53a51e97f8ed015e7d5ad0e1afc2ef3ab36e50b8</id><title>The featured card fills its own box</title><published>2026-08-05T18:00:45+09:00</published><updated>2026-08-05T18:00:45+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/53a51e97f8ed015e7d5ad0e1afc2ef3ab36e50b8.html"/><content type="text">The featured card fills its own box

Measured against the reference at 1440: their text block occupies 70% of the
label half with 64px of air above and below. Ours occupied 37%, with 96px. The
complaint was that our box is not roomy, and the cause was the opposite of what
that sounds like — three short lines stranded in the middle of a much taller
rectangle. More padding alone would have made it worse.

Four things fill it. The block gets a fourth line, &quot;Read post&quot;, underlined like
the doors elsewhere on this page, which gives the type a bottom edge instead of
leaving the description hanging in mid-air. The title steps up to 2.35rem and
takes text-wrap: pretty rather than balance, because balance minimises line
count and line count is where a text block gets its mass. Internal gaps go 0.6
to 1.15rem and padding to 3.4vw, which is the reference&#39;s 43px at this width.
The block is 198px now against 184 before, and it is anchored rather than
floating.

The writing room widens from the reading measure to the full one. The card was
950px while the project grid directly beneath it was 1235 — the narrowest block
on the page, overhung by 142px on each side, which reads as pinched whatever its
padding says. Both are 1235 now. The reading measure was the right container for
a ledger of prose and the wrong one for a two-column picture card; the ledger
keeps it on /posts/.

The media&#39;s min-height goes. It was clamp(11rem, 20vw, 15rem) and it never once
bound: the width and height attributes already state 16:9, so that ratio is the
row&#39;s floor at every width, and the label wins whenever it is taller. A rule
that cannot fire is worse than no rule, because the next person reads it as the
thing controlling the height.

Two things I looked at and did not do. Narrowing the project grid to match the
card instead drops it from three columns to two and doubles the section&#39;s
height. And the label&#39;s air grows with the card — 100px each side at 1235
against 61 at 950 — which is the price of the wider card; it reads as margin
rather than void because the block beneath it is anchored and the picture beside
it is large, but it is a real trade and a longer title is what would close it.
</content></entry>
<entry><id>urn:git:de7ce867449aeb946b35c6cbf08b2fb90a750182</id><title>Rebuild the font subset for two glyphs the card&#39;s comments added</title><published>2026-08-05T17:13:48+09:00</published><updated>2026-08-05T17:13:48+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/de7ce867449aeb946b35c6cbf08b2fb90a750182.html"/><content type="text">Rebuild the font subset for two glyphs the card&#39;s comments added

The subset covers the characters the site actually uses, and the previous commit
introduced 딸 and 떼 in the reasoning written beside the new rules. CI caught it
and refused to deploy, which is the check doing its job; I pushed without
reading its answer, which is not.
</content></entry>
<entry><id>urn:git:bb24d35016a9074be141b1fd69a7c2bb12f53dca</id><title>The newest post is one card, not a picture with a caption under it</title><published>2026-08-05T17:13:03+09:00</published><updated>2026-08-05T17:13:03+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/bb24d35016a9074be141b1fd69a7c2bb12f53dca.html"/><content type="text">The newest post is one card, not a picture with a caption under it

It was a centred picture with centred text beneath, at different widths and
different alignments, so the two read as separate things and the whole block ran
585px tall. It is a single bordered card now: picture on the left, label on the
right, the label vertically centred against it. 308px at 1440.

The label carries the full date rather than just the year. A year alone was the
right amount when the title sat under a centred picture and the eye had already
travelled; beside the title, in a column of its own, it had room to say when.

The picture fills its column and the label sets the height. Fixing the picture
at 16:9 in a two-column card makes the two halves disagree the moment a title
runs long, and one of them then has to grow a gap.

The title steps down a rung and rests at --ink-2, going to --ink on hover along
with the date to accent and the border one step lighter. That is the same
response the ledger rows below it give, so the card and the list beneath now
answer a cursor the same way.

Below 46rem the picture moves to the top at 16:9 and the border moves with it.
A post with no preview gets one column instead of an empty half.
</content></entry>
<entry><id>urn:git:b234ccd689964bc331dbee1e1be354397092362a</id><title>새로운 발걸음 — the Korean edition of the first post</title><published>2026-08-05T16:59:19+09:00</published><updated>2026-08-05T16:59:19+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/b234ccd689964bc331dbee1e1be354397092362a.html"/><content type="text">새로운 발걸음 — the Korean edition of the first post

Verbatim, verified the same way as the English: markup and whitespace stripped,
672 characters on both sides.

Two paragraph breaks were moved, no words. The supplied text broke mid-sentence
after &quot;아쉬울 때도 있지만,&quot; and then ran &quot;지난 20년&quot; onto the end of the sentence
that followed. Restoring both gives eight paragraphs, which is exactly what the
English edition has and how the two were written to sit beside each other.

/ko/posts/ is a list again rather than an empty page, and the switch on each
edition now finds the other.
</content></entry>
<entry><id>urn:git:2a27475a2bdf2daaa2772043a74d51f4a0f23576</id><title>A New Beginning, with a preview that plays on hover</title><published>2026-08-05T16:46:04+09:00</published><updated>2026-08-05T16:46:04+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/2a27475a2bdf2daaa2772043a74d51f4a0f23576.html"/><content type="text">A New Beginning, with a preview that plays on hover

The two posts that were here were mine, written to give the templates something
to render. They are gone. The first real post takes their place, verbatim.

The home page&#39;s top entry gets a 16:9 preview. It sits above the date and title
in the same language the project frames use — a border on the picture, the words
floating below it — and it plays when the pointer or the keyboard reaches the
link, stopping and rewinding to frame one when they leave. Frame one is the
poster, so the still you see before and after is the same still, and nothing
cuts.

The box does not move, resize or lift. What moves is inside the picture, which
leaves the rule about hover intact: the layout still never shifts under a
cursor.

Nothing is fetched until then. preload=&quot;none&quot; plus a poster means the front page
costs one 62KB still, and the 714KB clip is only requested by the hand that
asks for it. If the script never arrives, the still is what remains.

The source was 2.5MB at 1280x720 with an audio track nobody will ever hear.
Stripped, scaled to 960x540 and re-encoded at crf 32, it is 714KB and the
difference is invisible at four times the size it renders. VP9 was tried and
lost to H.264 on this material by 240KB, so there is one file rather than two.

The clip&#39;s path cannot live in the post&#39;s own front matter: listings carry only
title, description, url, weight and date, so the home page keeps a one-entry
catalogue keyed by URL, the same arrangement and the same reason as the project
catalogue. A post that is not in it simply has no preview. tools/check.py now
verifies that the URL names a real post and that both files exist, because a
typo there fails by showing nothing.
</content></entry>
<entry><id>urn:git:52adcf9765d08d4a3edc3739d2f43bd6cf271bae</id><title>egineer -&gt; engineer</title><published>2026-08-05T02:51:57+09:00</published><updated>2026-08-05T02:51:57+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/52adcf9765d08d4a3edc3739d2f43bd6cf271bae.html"/><content type="text">egineer -&gt; engineer

One letter, in the Korean About page&#39;s opening sentence. Lower case stays as the
owner wrote it.
</content></entry>
<entry><id>urn:git:38b7d5088b5b1b3f6891b395f0bd21764319b672</id><title>About, Korean: the owner&#39;s own copy, verbatim</title><published>2026-08-05T02:47:28+09:00</published><updated>2026-08-05T02:47:28+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/38b7d5088b5b1b3f6891b395f0bd21764319b672.html"/><content type="text">About, Korean: the owner&#39;s own copy, verbatim

Same treatment as the English page. Every word is the owner&#39;s; what was added is
the structure the paste had lost, and three links that change no words —
Projects and GitHub where the sentence asks you to check them.

Verified rather than eyeballed: the built page&#39;s prose, with markup and
whitespace stripped, is character-for-character equal to the text as supplied,
831 characters on both sides.

The two tables carry over from the English page unchanged. They are device names
and the supplied text ends by promising them, so leaving them out would have
made the page point at nothing.

Two asymmetries with the English page, both deliberate and both the owner&#39;s to
close: there is no Site section here, because none was supplied and inventing
Korean in someone else&#39;s voice is not a thing to do quietly; and the description
is the same English phrase the English page uses, because the owner&#39;s own first
sentence carries that phrase in English.
</content></entry>
<entry><id>urn:git:27a71a9af089d5a55b2a2c9116e47f7e0caac2fe</id><title>About&#39;s one-line answer is the same one the page gives</title><published>2026-08-05T02:34:53+09:00</published><updated>2026-08-05T02:34:53+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/27a71a9af089d5a55b2a2c9116e47f7e0caac2fe.html"/><content type="text">About&#39;s one-line answer is the same one the page gives

The lede said what the page was about; it says who the person is. That sentence
does four jobs from one string — the line under the title, the meta description,
the Open Graph description, and the snippet in this site&#39;s own search — so a
search result for &quot;about&quot; now answers the question instead of promising to.
</content></entry>
<entry><id>urn:git:9c3b2f1451a7a18d55fbe5f1bfe09ad7b9cf7576</id><title>About: the owner&#39;s own copy, verbatim</title><published>2026-08-05T02:27:31+09:00</published><updated>2026-08-05T02:27:31+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/9c3b2f1451a7a18d55fbe5f1bfe09ad7b9cf7576.html"/><content type="text">About: the owner&#39;s own copy, verbatim

Replaces the placeholder text I wrote when the page had nothing in it. Every
word is the owner&#39;s. The only thing added is the structure the paste had lost:
headings where headings were run into the sentence before them, and two tables
where TYPE and DEVICE had been flattened into a single line.

Three links, no words changed: Projects and GitHub in the sentence that asks you
to check them, and sqzass in the sentence that names it as this site&#39;s
generator.

Verified rather than eyeballed: the built page&#39;s text, with markup and
whitespace stripped, is character-for-character equal to the text as supplied —
1747 characters on both sides.

The front matter note about personal details being deliberately left blank goes
too. They are filled in now, by the only person who could.
</content></entry>
<entry><id>urn:git:73b2893016098bd7d33aa116f97afbbedd2244b7</id><title>There is no Korean home page</title><published>2026-08-05T01:39:42+09:00</published><updated>2026-08-05T01:39:42+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/73b2893016098bd7d33aa116f97afbbedd2244b7.html"/><content type="text">There is no Korean home page

Removing the language switch from the front door was the decision that the
front door is English. I then wrote Korean copy for a page that should not
exist. content/_index.ko.md is gone and /ko/ with it.

What stays Korean is what a reader came to read: posts, project pages, About,
and the two section listings those pages need as parents. The switch still sits
on each of them.

The brand mark now points at the English root rather than at the current
language&#39;s home, because for Korean that address is no longer a page. This is
the one link on the site where &quot;go home&quot; and &quot;the prefix that identifies a
section&quot; had been the same string; they are two variables now, and the comment
says which is which.

Nothing caught the resulting dead link. sqzass validates markdown `@/` links and
template variables, but not an address a template assembled, so the logo pointed
at a missing page on eleven pages and both the build and CI stayed quiet.
tools/check.py scans built HTML for internal links now, and CI runs it a second
time after the build, where public/ exists for it to read. It asks is_file()
rather than exists() — public/ko/ is a real directory because of the sections
underneath it, and the first version of this check passed it for that reason,
which is how the dead link got out in the first place.
</content></entry>
<entry><id>urn:git:70c24d5ad1232c2dd0713775d6c9fd4282292df1</id><title>The first screen says who I am, not what I make</title><published>2026-08-05T01:31:58+09:00</published><updated>2026-08-05T01:31:58+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/70c24d5ad1232c2dd0713775d6c9fd4282292df1.html"/><content type="text">The first screen says who I am, not what I make

The hero was a description of the work. It is a description of the person now,
which is what a reader arriving at a name expects the first screen to answer.

The Korean edition moves with it. Leaving it on the old copy would have made the
two front doors claim different things about the same person, and the front door
is the one page where that is most visible.
</content></entry>
<entry><id>urn:git:ad58cd79b12ccc896533bc6416d3611d65cf92ca</id><title>No grey plate under a hovered listing row</title><published>2026-08-05T01:10:46+09:00</published><updated>2026-08-05T01:10:46+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/ad58cd79b12ccc896533bc6416d3611d65cf92ca.html"/><content type="text">No grey plate under a hovered listing row

Hovering a post in the ledger no longer paints the row. A grey plate makes that
one row look like a different material, and scanning a list drags it from row to
row — one more thing moving in the place you are trying to read. What changes on
hover is what changed before it anyway: the date goes to accent and the title to
full ink. That is now the only thing that changes, which is what this site&#39;s own
rule says hover should do.

Three declarations retire with it: the transition that animated the plate, the
radius that rounded it, and the relative position that stacked it.

The horizontal padding and its matching negative margin stay. They were never
about the plate — they make the target wider than the text while leaving the
text where it sits. Keyboard focus falls through to the global focus ring, which
is a clearer signal than a background tint was.
</content></entry>
<entry><id>urn:git:07c79bbbda6312058691ff040354823643333aab</id><title>The rail&#39;s line is the signature orange, and the colophon is shorter</title><published>2026-08-05T00:57:45+09:00</published><updated>2026-08-05T00:57:45+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/07c79bbbda6312058691ff040354823643333aab.html"/><content type="text">The rail&#39;s line is the signature orange, and the colophon is shorter

The read portion of the rail is now #e4a242 in both themes. This is the one
place on the site where that colour stands at rest — everywhere else it appears
only under a cursor — and it is the right exception, because what it marks here
is how much of the piece you have read, which is a fact about you rather than a
piece of chrome.

One colour, not two. Progress is a single hue growing monotonically: the
sections above are full, the section you are in is the only partial one, the
ones below are an empty hairline. An earlier version drew the read sections in
ink and the current one in orange, which put the past at twice the weight of the
present and gave a reader two variables to rank with no way to order them. The
current section is identified by being the only bar that is neither full nor
empty, and by its name being the only one set in full ink.

The line is 6px from the window edge now instead of 10.

In light the orange sits at 2.12:1 against the page, which is low. That is the
cost of the colour and it is accepted knowingly: the rail is a supplementary
indicator, the table of contents that has to work is the one rendered in the
document for narrow screens and for no JavaScript at all, and the current
section is announced by aria-current rather than by hue.

The colophon loses about a quarter of its height — padding from 3/4rem to
2/2.5rem, row gap from 1.25 to 0.9rem, 262px down to 201px. Chrome is the way
out of a page, not another page; at full height it read as somewhere the
document started over.
</content></entry>
<entry><id>urn:git:d9fd02de19096b9834cc37cd03a8725672e1b2f0</id><title>Thicker ticks, closer to the edge</title><published>2026-08-05T00:41:15+09:00</published><updated>2026-08-05T00:41:15+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/d9fd02de19096b9834cc37cd03a8725672e1b2f0.html"/><content type="text">Thicker ticks, closer to the edge

The rail&#39;s marks go from 1px to 2px and sit 10px from the window edge instead
of 19px. Nearer the scrollbar is where this thing belongs: the further it drifts
into the margin the more it reads as an ornament floating in white space, and
the closer it sits the more it reads as scroll furniture, which is what it is.

2px is the only line in this stylesheet that is not a hairline. It earns the
exception by being the one line that carries a value rather than dividing two
things, and at 1px the difference between a read section and an unread one was
carried by three greys inside a single pixel column.

The label column gets 8px wider as a side effect, since the ticks gave back
what the padding no longer takes.
</content></entry>
<entry><id>urn:git:a9125a5d0fda3885279d3a1e1bb84f7848175b92</id><title>Delete a comment describing a rule that is gone</title><published>2026-08-05T00:30:48+09:00</published><updated>2026-08-05T00:30:48+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/a9125a5d0fda3885279d3a1e1bb84f7848175b92.html"/><content type="text">Delete a comment describing a rule that is gone

The reveal note still said the tick steps one rung up in colour. It stopped
doing that when the hover rule came out, and the paragraph directly beneath it
already explains why. A comment that describes code which no longer exists is
worse than no comment: the next person reads it as intent and puts the rule back.
</content></entry>
<entry><id>urn:git:48884c0e21f472955ff9f726aa16b41c1b11aad3</id><title>Two colour steps in the rail that pointed the wrong way</title><published>2026-08-04T21:15:57+09:00</published><updated>2026-08-04T21:15:57+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/48884c0e21f472955ff9f726aa16b41c1b11aad3.html"/><content type="text">Two colour steps in the rail that pointed the wrong way

Both were mine, both from picking a token by name instead of by luminance.

The tick&#39;s hover feedback did nothing. --rule-3 to --ink-4 is 1.78:1 to 1.72:1
in light — fainter, not brighter — and 1.76:1 to 1.77:1 in dark, which is
nothing at all. The two tokens sit at almost the same luminance in both themes
and there is no rung between the resting hairline and the ink the read sections
use. So the tick no longer responds to hover: four names appearing at once is
already an unmistakable answer, and when there is no room for a device you
remove it rather than shrink it.

The labels were --ink-3 at 0.72rem, which is 4.23:1 in light — under AA for
13.7px text — and hovering one turned it accent at 2.12:1, so touching a name
made it harder to read. That is the second place in this component where the
accent was doing the opposite of its job. Labels rest at --ink-2 and go to --ink
on hover; the current one is still --ink, and what separates it from a hovered
one is not colour but the tick, which is the only partially filled bar in the
column. The rail now contains no accent at all.
</content></entry>
<entry><id>urn:git:ee2330fa699f09ba969f3e21e6b5e75aac5395bb</id><title>Fix the reading rail: it was 400px from where a hand goes</title><published>2026-08-04T21:07:37+09:00</published><updated>2026-08-04T21:07:37+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/ee2330fa699f09ba969f3e21e6b5e75aac5395bb.html"/><content type="text">Fix the reading rail: it was 400px from where a hand goes

Measured on the live page at 1440x757, the rail drew a 266x484 block in the
right margin and only 14% of it responded to a mouse. The only live surface was
a 39px strip around three 1px lines; everything else, including the entire area
the labels appear in, was pointer-events: none. Worse, the labels were reachable
only from the 28% of a segment&#39;s height that overlapped the label&#39;s own band —
enter the tick anywhere else, move toward the name you just revealed, and it
deleted itself before you arrived. An interaction that works about a third of
the time reads worse than one that never works.

Four things changed.

The rail is pinned to the window edge instead of the text column. Anchoring it
to the column put it 311px from the edge at 1440 and 551px at 1920 — nowhere a
hand goes. The strip a hand crosses reaching for the scrollbar is the most
travelled empty space on a page, and the rail now lives in it. The whole box is
the trigger, so the labels appear when the cursor enters the margin and stay up
while it travels to any of them.

Ticks moved outboard and labels inboard, right-aligned against them. Names now
run toward the text instead of away from it, and four right-aligned lines hug
the rail as one list instead of floating as three orphan phrases.

There is a first segment for the introduction, from the top of the prose to the
first heading, labelled with the post&#39;s title and linking to #content, the
anchor the skip link already uses. Without it, 34% of the article belonged to no
segment and the rail was inert for the first 750px of scroll — you arrived, you
started reading, and nothing moved. It also gives the proportional map something
to say: with three near-equal sections the segment heights varied by 22% and the
map was indistinguishable from a tick list.

The accent is out of the rail. As drawn, the current section was 2.1:1 and the
sections already read were 4.2:1 — the past twice as loud as the present, and
the one mark carrying &quot;you are here&quot; the faintest thing in the widget. It is one
ordered luminance ramp now: unread hairline, read ink, current full ink, and the
current segment is still the only partially filled one. Accent goes back to
hover, which is where this site&#39;s rule says it belongs.

Kept, because measuring the two side by side said to: grid rows rather than
absolutely positioned labels, so a label can never end up beside the wrong tick
and nothing desyncs during a resize; the reading line derived from the heading&#39;s
own scroll-margin-top, so &quot;you are here&quot; and &quot;clicking goes here&quot; come from one
declaration; getElementById on the raw href, which does not throw on a Korean
id; and the inline list that keeps working with no JavaScript at all. Still
refused: hiding the native scrollbar, and the drag-scrub that only makes sense
once you have.
</content></entry>
<entry><id>urn:git:1d31969a52cd2c0a49990857a1566c2ed3c57a13</id><title>The language switch belongs to a document, not to a page</title><published>2026-08-04T20:21:31+09:00</published><updated>2026-08-04T20:21:31+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/1d31969a52cd2c0a49990857a1566c2ed3c57a13.html"/><content type="text">The language switch belongs to a document, not to a page

Off the home page and off both listing pages. It stays on posts, project
pages and About — the places where there is a piece of writing with a
counterpart to go to.

The distinction is the whole reason it left the masthead. On a document, &quot;KO&quot;
means go to the other edition of this thing you are reading. On a listing or
the home page there is nothing being read, so the same two letters read as a
site-wide setting again, which is what the masthead switch was and what was
wrong with it.

The home hero goes back to the spacing it had before, since the row that was
crowding it is gone.
</content></entry>
<entry><id>urn:git:37e3f907fb08dd61accae44aacc2bb987b00d2d3</id><title>Move the language switch into the page, add a reading rail</title><published>2026-08-04T20:10:14+09:00</published><updated>2026-08-04T20:10:14+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/37e3f907fb08dd61accae44aacc2bb987b00d2d3.html"/><content type="text">Move the language switch into the page, add a reading rail

The switch was in the masthead, where it read as a global setting — &quot;show me
this site in Korean&quot;. What it actually does is go to the other edition of the
document you are reading. Moving it into the page makes that meaning obvious
from its position, and leaves the chrome holding only the three sections and
search.

It sits with the date on posts, under the title elsewhere, under the badges on
a project page, and above the door on the home page. Labels are EN and KO in
both languages: chrome here is English, and a two-letter code reads the same to
someone who only reads one of them, which &quot;English 한국어&quot; does not. The order is
always EN then KO — putting the current language first would swap the two words
every time you switched, so the thing you just clicked moves out from under the
cursor. The language you are reading is the brightest thing in the row; the one
you can go to is a link with an empty underline that fills with accent on
hover. The reference site has this inverted, so working out where you are means
comparing two greys.

The reading rail is the table of contents in its second form. Above 1280px it
stands in the right margin: one vertical hairline per heading, each as tall as
that section&#39;s share of the article, so it maps the document rather than
listing it — a list says how many parts there are, a map says which part is
half the piece. Sections you have read are ink, the one you are in is a
partially filled accent stub, the rest are the same hairline the inline TOC
uses for its left rule. Hovering reveals the headings in place: nothing widens,
nothing slides, the labels fade up and the ticks step one rung along the
hairline ladder, all at the sheet&#39;s single duration.

Position comes from scroll arithmetic against boundaries measured once, not
from an IntersectionObserver, which is why clicking a heading does not fight
the smooth scroll — during the jump you really are passing through those
sections. The reading line is offset by the heading&#39;s own scroll-margin-top, so
&quot;you are here&quot; and &quot;go here&quot; come from one declaration and cannot disagree.
Row heights are a grid track string, which hands overlap to the browser and
deletes the hand-written collision solver the reference needs.

Below 1280px the rail does not exist and the inline list renders in flow, with
its nesting intact. The list is also what remains if the script never arrives —
the rule that hides it is behind a class the script adds. There is exactly one
table of contents in the accessibility tree at every width, and the native
scrollbar stays, which is what lets the rail be nearly invisible at rest.

Both posts turn their table of contents on; they have three headings each and
were the reason the partial existed.
</content></entry>
<entry><id>urn:git:b91126d702a6b51845c05b8b90d249245fdd2bea</id><title>Revert the project detail page, keep the masthead fix</title><published>2026-08-04T19:10:00+09:00</published><updated>2026-08-04T19:10:00+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/b91126d702a6b51845c05b8b90d249245fdd2bea.html"/><content type="text">Revert the project detail page, keep the masthead fix

The document-style rewrite is out. The split hero, the metrics band, the
numbered feature grid, the terminal with its title bar and the closing call to
action are back, along with the twelve project files and the CSS that draws
them. The owner preferred the denser page and that settles it.

What stays from that commit is the part that had nothing to do with it: below
736px the masthead could not fit its contents and said so by wrapping the
language label onto three lines. Chips no longer wrap, the centre axis is given
up when it costs more than it buys, the search control shows a word where a
keycap means nothing to a touch screen, and below 544px GitHub leaves the bar
because the colophon has the same link and a truncated nav label is worse than
one less duplicate.
</content></entry>
<entry><id>urn:git:2d976c57463c80fe17bbc4005d53735d6755cb25</id><title>Rebuild the project page as a document, not a landing page</title><published>2026-08-04T18:56:55+09:00</published><updated>2026-08-04T18:56:55+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/2d976c57463c80fe17bbc4005d53735d6755cb25.html"/><content type="text">Rebuild the project page as a document, not a landing page

The old page ran back link, split hero, metrics band, feature grid, terminal,
call to action. That is a product landing page, and it was the reference&#39;s
sequence move for move — the reader performed the same six steps in the same
order on both sites. Everything below is downstream of changing that.

Every other page here opens the same way: centred head, then a `+++` fence.
The project page opened off the centre axis instead, with text left and a
framed square right, and it was the only page on the site missing the fence —
the page about the generator the fence refers to. It opens like the rest now.
The medallion goes with the split, and so does the &quot;no image&quot; plaque on detail
pages: a gallery frame has a slot to fill, a detail page has nothing to fill,
so it stops drawing a box around an absence. The plaque stays on the index.

A spec table replaces the badge row and the big-number strip. Those printed
the same value three times — Rust in the eyebrow and again in a badge, MIT in
a badge and again as a metric, 0.1.0 twice. Now once. Setting a star count of
zero at forty-six pixels is a statement about the project; &quot;runtime
dependencies · 0&quot; in a spec row is a fact about the binary, and it is the same
number. The repository and star rows are generated from the front matter
scalars rather than authored, because those two lines are what stars.py
rewrites and it can only rewrite one copy.

The terminal loses its title bar. Three traffic-light dots and a `zsh` label
are a picture of Terminal.app; what is in the box is real output, so it sits in
the same recessed box the site already uses for machine output.

The numbered card grid becomes the ledger. Six cards in a hairline lattice with
`01`–`06` in the corner is the most reproduced object in this genre. The
numbers survive — the copy earns them, six ordered decisions each of which is a
failure that happened somewhere else first — but they move to a margin column
in the ledger geometry the post list already uses.

The closing band becomes one sentence. The pair of buttons now appears once,
in the head, where the reader is when they decide.

Tiers now differ by order and width rather than by section count. A landing
page argues from its spec; a brief page is a piece of writing with its spec
appended as a footnote, which is what four of these six actually are. Landing
widens to 52rem exactly twice, brief never widens, so two screens tell you
which you are on without counting sections.

Net CSS is a deletion. Nothing here is a new component: the page is built from
.page-head, .fence, .crumbs, .eyebrow, .prose, .prose table and the ledger
grid. The spec and register selectors join existing rules rather than restating
them, so fixing one fixes both.

Also fixes the masthead below 736px, where it could not fit and said so by
wrapping the language label onto three lines. Chips no longer wrap, the centre
axis is given up when it costs more than it buys, the search control shows a
word where a keycap means nothing, and below 544px GitHub leaves the bar — the
colophon has the same link, and a truncated label is worse than one less
duplicate.
</content></entry>
<entry><id>urn:git:0b80e405218460c411cd54951263d6172600e860</id><title>Light by default, one accent, English chrome in both languages</title><published>2026-08-04T18:28:11+09:00</published><updated>2026-08-04T18:28:11+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/0b80e405218460c411cd54951263d6172600e860.html"/><content type="text">Light by default, one accent, English chrome in both languages

The accent is #e4a242 in both themes now. It loses contrast on the light
surface, which is a real cost and worth naming: it is only ever used on hover,
focus and the current item, and every one of those places also changes
something structural — an underline, a border, the tick under a nav item — so
nothing on this site is carried by that colour alone. Where the accent becomes a
background rather than ink, --on-accent holds the dark ink that sits on top of
it; ::selection was painting near-white text on orange in the light theme.

Light is the default now. It was only ever dark because the reference was.

Korean keeps English chrome. Navigation, footer, controls and door links stay in
English in both languages; what translates is what you came to read — titles,
descriptions, prose. Section labels come from i18n by matching the URL rather
than from the section title, because a section title is content and follows the
page language. Unknown sections fall back to their title.

That also shrinks the Korean typographic reset from eighteen selectors to eight.
It exists to undo letter-spacing, uppercase and monospace where Hangul appears;
chrome that is now always English needs none of it, and leaving it on made the
nav lowercase on Korean pages only.
</content></entry>
<entry><id>urn:git:dc6e1b2b71cefc9d93fa9b88c9f2d68a35d450e9</id><title>Rebuild the font subset for two new glyphs</title><published>2026-08-04T18:10:46+09:00</published><updated>2026-08-04T18:10:46+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/dc6e1b2b71cefc9d93fa9b88c9f2d68a35d450e9.html"/><content type="text">Rebuild the font subset for two new glyphs

The last commit added 돋 and 캡 in a template comment. The subset carries only
the characters the site uses, so CI refused the build — which is the check
doing exactly what it is for.
</content></entry>
<entry><id>urn:git:9fb067957c8ac7d4db853afac42956ae10f94a0a</id><title>Take the accent from the portrait, centre the nav, drop the magnifier</title><published>2026-08-04T18:09:48+09:00</published><updated>2026-08-04T18:09:48+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/9fb067957c8ac7d4db853afac42956ae10f94a0a.html"/><content type="text">Take the accent from the portrait, centre the nav, drop the magnifier

The accent is #e4a242, sampled off the backdrop of the photograph on the about
page rather than chosen. hsl(36, 75%) — the same hot register every other
property here sits in, and the one colour on the site that is demonstrably the
owner&#39;s. It is complementary to the cool near-black, so the places a hand
touches lift cleanly off it: 9.07:1 on the dark surface. The light theme keeps
the hue and drops the lightness to #935f10, because an orange that reads at 9:1
on near-black falls to under 2:1 on near-white. The theme is called marigold now.

The masthead becomes a three-column grid. It was a flex row with the nav on
margin-inline: auto, which centres the nav in the space left over rather than on
the page — so it sat off-axis by whatever the brand and the tool cluster differ
by. The outer columns are 1fr each and measure identically at 444.281px, which
puts the nav on the same centre line as the page title, the fence and the
frames.

The magnifying glass leaves the search trigger. What is left is the keycap,
which says what to press — more useful than a picture of a lens — and the word
&quot;search&quot; was already carried by aria-label for anyone who needs it.

.claude/ is ignored and untracked. Eighty-six files of editor tooling had been
committed; they are tools, not the site. They stay on disk.
</content></entry>
<entry><id>urn:git:68d40c0d55d2ac54523c8791758eaed4c13d0f50</id><title>Hover changes colour and nothing else</title><published>2026-08-04T17:48:46+09:00</published><updated>2026-08-04T17:48:46+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/68d40c0d55d2ac54523c8791758eaed4c13d0f50.html"/><content type="text">Hover changes colour and nothing else

Every scale and shift on hover is gone: the brand mark, the tiles, the cells,
the frames, the medallion, the link icons, the social icons, and the gap that
opened between a button&#39;s label and its arrow. Hover moves colour now, the way
the rest of the site already did. Size changing under the pointer pulls the eye
to it, and on this site the place the cursor is passing over is usually the
place someone is reading.

That leaves --tr-light with no consumers, so it goes too. One tempo, one curve.
The tooltip fades in without sliding, for the same reason.

Picked up the ledger gutter while in there — it was still on the fixed 6.5rem
and 1.5rem the last pass was supposed to hang off the viewport.

Favicon: white plate, black lines, and the mark nearly fills the square. Padding
costs more than stroke does at 16px. The line art is dilated by one pass before
any of the assets are written, because the original stroke is thin enough that
antialiasing eats it at masthead size and at every favicon size. Both favicon
variants are now the same white plate — an opaque white square is legible
against a light tab and a dark one, so there is nothing left for the media query
to choose between, though the two files stay so the link tags do not have to
change.

/projects/ drops the &quot;Terminal tools&quot; group. sqzass and ommp were already the
two featured frames directly above it, so the section restated the top of the
page with smaller type.

The colophon says what built the page and who holds the copyright. The year is
written by hand: sqzass has no now(), because a template that can read the clock
cannot produce the same bytes twice.
</content></entry>
<entry><id>urn:git:ec8ae7cb4bc613c67f6ec7381334aaaab3a0c181</id><title>Declare the weight tokens the last commit forgot</title><published>2026-08-04T17:33:59+09:00</published><updated>2026-08-04T17:33:59+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/ec8ae7cb4bc613c67f6ec7381334aaaab3a0c181.html"/><content type="text">Declare the weight tokens the last commit forgot

The previous commit tokenised the ladder at every call site but never landed the
:root declarations — the edit that added them died before it wrote the file, and
only the html[lang=&quot;ko&quot;] redeclaration survived. So English pages resolved
var(--w-display) and friends against nothing, the declarations were invalid at
computed-value time, and the display type fell back to 400. Korean was correct
by accident, because its block declared the tokens locally.

Two rules were left holding literals for the same reason and are converted now.
Prose headings join the ladder as well: h2 at section, h3 at item, h4 at label,
which is the same rule the display scale follows — the bigger it is, the thinner
it gets.

Verified by reading getComputedStyle in a browser rather than by reading the
sheet, which is what would have caught it the first time. Every rung on five
English pages and both Korean pages resolves to its intended value, and Korean
letter-spacing computes to normal.
</content></entry>
<entry><id>urn:git:d67d61a799a2b42ecec8eda8b01d62ff50301868</id><title>Re-pitch the weight ladder, thin the masthead, drop the social labels</title><published>2026-08-04T17:29:03+09:00</published><updated>2026-08-04T17:29:03+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/d67d61a799a2b42ecec8eda8b01d62ff50301868.html"/><content type="text">Re-pitch the weight ladder, thin the masthead, drop the social labels

Wave 3, plus two things asked for directly.

The ladder was six rungs — 230, 250, 280, 300, 350 — each written at the
selector that used it, and each one matching the reference&#39;s rung for rung
along with the same positive tracking. Six ad-hoc numbers are not a ladder, they
are a coincidence that happens to be someone else&#39;s. It is four tokens now,
evenly spaced and wider at both ends: 180 for display, 260 for section heads,
340 for item titles, 420 for the smallest labels. The top end goes thinner and
the item titles go heavier, so the page has more range between its largest and
smallest type while still having no bold anywhere — the heaviest rung is 420.

Tracking collapses to two values for the same reason. Light type set large wants
air; the need falls away as the weight climbs. --track-air on the two light
rungs, --track-set on the two heavy ones, and nothing chosen per selector.

Korean redeclares all six tokens in one block instead of overriding weight at
each selector. Hangul carries far more stroke at the same weight, so it needs
the whole ladder a step up, and tracking has to go to zero — the value that
gives Latin room pulls syllable blocks apart and makes one word look like
several. Caught that in a screenshot after the first pass; the tokens were
being inherited by display text that had never needed them before.

The masthead was 4.75rem, which is about 90px at the top of the root clamp.
It is 3.5rem now, the height the sqzass docs use. It is chrome, not content.

Footer socials lose their words. GitHub and Instagram are two of the few marks
that read on their own, so the label was doing nothing but adding width; the
name lives in aria-label and the drawn tooltip. They press on hover like
everything else does.
</content></entry>
<entry><id>urn:git:cea848899c151f83c4122f4d3eb211b2716acd8c</id><title>Hand the ornament over: fence, squeeze, Ctrl+/, socials</title><published>2026-08-04T16:45:10+09:00</published><updated>2026-08-04T16:45:10+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/cea848899c151f83c4122f4d3eb211b2716acd8c.html"/><content type="text">Hand the ornament over: fence, squeeze, Ctrl+/, socials

Wave 2 of the differentiation. Wave 1 moved the colours; this moves the devices
that were invented somewhere else.

The plumb line above page titles is gone. It was a 1px vertical gradient with
the reference&#39;s clamp, direction and stops, and the Korean comment attached to
it — &quot;the one decorative-looking thing here, and it is not decoration&quot; — was
written about a different device entirely. That device is the +++ fence, and it
is now where it belongs: between the title block and the body, once per page,
marking the same boundary it marks in the source file. Every page on this site
literally is a sqzass document that opens with +++.

Hover stops being light and starts being pressure. The radial pools under tiles
and cells, and the directional wash under ledger rows, were the reference&#39;s
named central primitive down to the alpha and the gradient stop. They are
replaced by scale(0.988) — the value the sqzass landing already uses, under a
comment that says the squeeze is not decoration, it is what the product does.
The names in this house all have their vowels pressed out. Pressing is the
point.

Artwork stops desaturating. Grayscale-at-rest arrived from the reference and
from nowhere else; ommp ships full-colour screenshots and argues for it. The
portrait and the covers now rest in colour, and the ommp cover finally looks
like ommp.

Section headings lose their flanking hairlines, and the class loses the name it
borrowed — .wing came from the reference&#39;s own comment. Whitespace was already
doing that job; one device per job.

Search moves to Ctrl + / , the binding the sqzass docs already ship, matched on
e.key rather than e.code because the layouts where slash needs a modifier put
the physical key somewhere else. It toggles, it stays out of the way while you
are typing in a field, and the Cmd-K binding is gone so there is one shortcut
and one label. The hint becomes an actual keycap — thin border, 3px radius —
because it is the one control that names a key, and the trigger holds its width
so it does not move under the pointer when the label changes on macOS.

The colophon gains GitHub and Instagram on their own row. Inside links and
outside links on one line blur which is which.

One fix on the way through: the ledger measure was set to 68ch, which resolves
against the body font on a container and came out half the intended width, so
titles wrapped. It is derived from --read now instead of picked.
</content></entry>
<entry><id>urn:git:67344fd68a8204c4277abe01aba03b9a7666fa91</id><title>Retint the theme: jade on a cool near-black</title><published>2026-08-04T16:39:52+09:00</published><updated>2026-08-04T16:39:52+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/67344fd68a8204c4277abe01aba03b9a7666fa91.html"/><content type="text">Retint the theme: jade on a cool near-black

Name the theme while renaming its colours. hwaro catalogues 224 example sites
and hahwul.com is one of them; this is sqzass&#39;s first, and it is called jade
after the only colour in the sheet.

The tell was saturation. hahwul&#39;s brass is hsl 34%; every property in this house
is hot — the blog at 100%, the sqzass landing at 100%, the sqzass docs at 82%,
ommp&#39;s tabs in the same register. This site shipped a 52% tan, which is the
wrong family. The surfaces had the same problem from the other direction: ommp
is blue-violet lifted straight from its own BG_DARK, the blog is blue-green, the
sqzass docs are blue-black, the landing is warm brown. Only hahwul&#39;s is a pure
neutral, and this site had copied it byte for byte at #010102.

Jade is picked by elimination rather than taste: peach and coral belong to
sqzass, amber to the blog, neon pink and cyan and violet to ommp. Blue-green was
the one register nobody was using. It keeps the rule all three of those sheets
state independently — absent at rest, present only on hover, focus and the
current item.

Also swept the values that were identical to the reference rather than derived
from anything here: the negated mask feature test, saturate(140%), a 60rem
ledger measure, a body clamp that duplicated the root&#39;s, and the --glow token,
whose name came with the brief it was lifted from. It is --ink-rgb now; the
reason for keeping a bare triplet instead of a hex is still good and is still
written down.

No template changed and nothing moved.
</content></entry>
<entry><id>urn:git:42e8483ffe3c6bc0558b783432f5cf6942bc2d4c</id><title>Finish the gallery: lattice, per-project accents, tooltips</title><published>2026-08-04T14:48:03+09:00</published><updated>2026-08-04T14:48:03+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/42e8483ffe3c6bc0558b783432f5cf6942bc2d4c.html"/><content type="text">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&#39;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&#39;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&#39;s.

Brief pages drop a step of title scale and lose the hero&#39;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.
</content></entry>
<entry><id>urn:git:33bf676e4aa49ca3add0a290ce68fc197a8aa2cb</id><title>Drop rust-cache from the deploy workflow</title><published>2026-08-04T14:39:16+09:00</published><updated>2026-08-04T14:39:16+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/33bf676e4aa49ca3add0a290ce68fc197a8aa2cb.html"/><content type="text">Drop rust-cache from the deploy workflow

There is no Cargo.toml in this repository, so the action cannot find a
workspace and logs an error on every run. The crate worth caching lives in
sqzass, not here.
</content></entry>
<entry><id>urn:git:25a03f8e5d331ca06b3752fb59a5705cb91277d5</id><title>Rebuild the visual layer as a centered gallery</title><published>2026-08-04T14:36:50+09:00</published><updated>2026-08-04T14:36:50+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/25a03f8e5d331ca06b3752fb59a5705cb91277d5.html"/><content type="text">Rebuild the visual layer as a centered gallery

The site copied hahwul.com&#39;s sitemap and component list, then rebuilt every
visible layer in a different grammar: flush-left where the reference is
centered, bordered single-column rows where it packs a borderless tile grid,
and weight-800 mono display where its entire identity is ultralight. Same
parts, opposite composition. This rewrites the surface.

Type. A variable face at 100-900 replaces the OS fallback, so sub-400 weights
exist at all: page titles 230, statements 250, wing titles 300, tiles 350, with
positive tracking. No bold anywhere. Latin and Hangul ship as separate
unicode-range subsets, so an English page fetches 62 KB and never touches the
116 KB Korean file. The Korean subset carries only the glyphs the content
actually uses; tools/fonts.py rebuilds it and CI fails the build when a new
character has no glyph.

Palette. Neutral near-black replaces the blue-shifted graphite, and the two
saturated accents worn at rest become one warm tint that appears only on hover,
focus and the current item. Filled buttons fill with ink, not accent.

Projects. The list becomes a wall: centered tiles with no borders and no
dividers, a light pool rising under the cursor, tracks capped and centered so a
two-item group does not hug the left of a three-column grid. Section headings
become centered wing titles flanked by hairlines at 7rem of air — they were
0.72rem plates, smaller than body text, which is why the page read as one
continuous list instead of stanzas. Featured cards lose their frames: only the
media is framed, the caption floats under it, and the cover desaturates at rest.

Home opens on a full-viewport centered threshold — mark, one sentence, one
underlined door — instead of a left-aligned copy block.

Also: the site is &quot;sqzer&quot;, not the GitHub account name. Marks render pure white
on dark and pure black on light, never grey, which read as a disabled state.
Favicons sit on opaque rounded plates because a transparent line drawing
disappears into whichever tab colour the browser is using. Missing artwork
renders as a &quot;no image&quot; box at the size the real image will take, so the frames
that need art are visible as gaps rather than improvised out of type.

Star counts are baked into front matter by tools/stars.py and refreshed daily
by a scheduled workflow. Fetching them in the browser costs a request against a
60/hour anonymous limit shared by everyone behind the same NAT, and fetching
them during the render would end the guarantee that two builds produce the same
bytes. They show at zero, because that is the number.
</content></entry>
<entry><id>urn:git:70e408e46b8d4af527a21b99dd0924270a7aee0b</id><title>Add the marks, the portrait, and favicons</title><published>2026-08-04T00:47:59+09:00</published><updated>2026-08-04T00:47:59+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/70e408e46b8d4af527a21b99dd0924270a7aee0b.html"/><content type="text">Add the marks, the portrait, and favicons

The brand mark, the sqzass mark and the profile photo, plus a favicon set the
site did not have at all.

Both logos are black line art, and the shape is in the luminance rather than the
alpha — the PNGs carry a fully opaque alpha channel over a white background.
Reading them as alpha produced a solid rectangle, and cropping to the alpha
bounding box trimmed nothing. They are converted by inverting the luminance,
which gives a real mask and a real bounding box: 2816x1536 of mostly margin
becomes 1121x1074 of drawing.

They ship as CSS masks rather than images. Black lines on a near-black field are
invisible, and a project&#39;s own palette has no reason to win an argument with the
page. As masks they take currentColor, so they follow the theme, the hover state
and the light build with no second asset. 5 KB and 26 KB.

The ommp asset is a wide colour lockup with the product name in it, so it is a
cover rather than a mark. That splits the card artwork into three cases —
cover, mark, name — and all three now hold the same 16:7 box, because a card
whose media is shorter than its neighbour&#39;s starts its body on a different line
and the row reads as broken.

The portrait gets its own template. In the markdown body it would sit between
paragraphs and need its width decided per document; in the header there is one
place and one size. It rests desaturated: the orange backdrop is the loudest
colour on the site and it does not need to win the page on arrival.
</content></entry>
<entry><id>urn:git:228a025383db740cc8734827ffd86995b0f88639</id><title>Fix paragraph spacing and the brief-tier hero</title><published>2026-08-03T23:50:10+09:00</published><updated>2026-08-03T23:50:10+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/228a025383db740cc8734827ffd86995b0f88639.html"/><content type="text">Fix paragraph spacing and the brief-tier hero

`.prose p { margin: 0 }` is a class plus a type selector, so it outranked
`.prose &gt; * + *` and killed the gap between every paragraph on the site. Both
rules are now (0,1,0) and source order decides, which is what the cascade is
for. Headings keep their larger top margin because their own rule is still
more specific.

A brief project lives inside the 46rem reading column, and putting the hero
aside in there squeezed the tagline into a narrow gutter — for a project with
no logo, to make room for a square with its own name faintly printed in it.
Brief pages now use the full width and drop the aside.
</content></entry>
<entry><id>urn:git:d1ebabf7fc74237da8aa33ff206fa84b81464070</id><title>Build the site</title><published>2026-08-03T23:48:29+09:00</published><updated>2026-08-03T23:48:29+09:00</updated><author><name>sqzer</name><email>110329244+sqzer-x@users.noreply.github.com</email></author><link rel="alternate" href="https://oni.sqzer.com/www/commit/d1ebabf7fc74237da8aa33ff206fa84b81464070.html"/><content type="text">Build the site

sqzer.com — projects, technical posts, an about page, in English and Korean.
Built with sqzass and deployed to GitHub Pages.

Structure follows hahwul.com, which was the reference: a ledger for posts with
a fixed date gutter and year separators, a projects index that opens with large
cards and then lists by group, project pages in two tiers, and section headers
whose label is set smaller than body text.

Colour and type do not follow it. The field is a cool graphite rather than a
near-black, and instead of one warm tint there are two accents that carry
meaning — teal for what is live or primary, gold for what is marked or
archived. Type is a system stack for both scripts plus JetBrains Mono as a real
second voice for dates, badges, commands and the wordmark. A Hangul webfont
with usable coverage is about 2 MB; the system already has one that is correct.

Notes on the parts that are not obvious:

- No star counts. The repositories have none, and &quot;0 ★&quot; is worse than nothing.
  The facts strip carries version, licence, platform and dependency counts
  instead — things a reader of a Rust tool actually wants and can verify.
- The projects catalogue lives in the index page&#39;s [extra] because listings
  carry only title, description, url, weight and date. tools/check.py asserts
  the catalogue and the pages match in both directions, since [extra] is the one
  reference sqzass does not check.
- Inline tables are one line each. TOML 1.0 does not allow them to wrap; the
  Rust parser accepts it as an extension and Python&#39;s tomllib does not, so the
  long ones are [[extra.features]] blocks.
- The scroll reveal hides behind a `js` class set by the inline head script, so
  a failed script load leaves everything visible rather than blank.
- Korean reverts the tracked, uppercased and monospaced treatments: letter
  spacing pulls syllable blocks apart, text-transform does nothing, and a mono
  family renders every gap between 어절 at double width.

Search is the index sqzass emits, scanned for substrings — 성기 finds 생성기,
which no word index would.
</content></entry>
</feed>
