diff --git a/web/scripts/players.test.mjs b/web/scripts/players.test.mjs index 0f94117..c9350ec 100644 --- a/web/scripts/players.test.mjs +++ b/web/scripts/players.test.mjs @@ -226,3 +226,20 @@ test("neither Challenge nor the follow tick is drawn about yourself", async () = // the appview about. assert.match(mark[0], /session\.did !== actor\.did/); }); + +// The display face is applied through one closed list of selectors, and a +// heading that is not named in it silently inherits the body face — which is +// how a player's handle shipped set in the wrong family. This holds the one +// heading on this page to that list. +test("a player's handle is set in the site's loud face", async () => { + const css = await readFile(`${src}styles.css`, "utf8"); + const list = css.slice( + css.indexOf(".brand-name,"), + css.indexOf("font-family: var(--font-display);"), + ); + assert.match( + list, + /\.profile-name,/, + "the handle is not in the display-face list, so it falls back to body text", + ); +}); diff --git a/web/src/styles.css b/web/src/styles.css index caa34d6..8d6d96b 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -355,6 +355,7 @@ body { .brand-name, .hero-copy h1, .page-head h1, +.profile-name, .daily h2, .signin h2, .card h2, @@ -421,6 +422,13 @@ body:has(.camo-editor) { --shell: 70rem; } +/* A player's page is a picture beside a column of type, and the reading + measure is the width of the column alone: at that width the handle and the + portrait fight over the same 30rem. */ +body:has(.profile) { + --shell: 46rem; +} + /* A match reads across one line — id, status, when, the way in — and the reading measure is not wide enough to hold four things without them colliding. */ @@ -2972,20 +2980,39 @@ footer .debug { gap: 1.5rem; } +/* The column the name is measured against, rather than the window: what runs + out beside a picture is this, and it is a good deal narrower than the page + it sits on. The site already sizes three other things this way. */ .profile-who { display: flex; flex-direction: column; gap: 0.9rem; min-width: 0; + /* Take the row's spare width before the container is measured: an + inline-size container stops sizing itself from its contents, so a flex + item that is one and does not claim its share collapses to nothing and + takes the name down to one letter a line. */ + flex: 1; + container-type: inline-size; } /* A handle is a domain and can be long, so it sizes off the column rather than off the window, and it breaks rather than pushing the page wide. */ +/* A handle is a domain and can be long, and it is the one thing on the page + that must stay readable at any width. + + Sized off its own column, which is what it has to fit in: a cqw with no + container above it silently measures the window instead, and the window is + not what runs out beside a 8.5rem picture. That was how "@permadeath.com" + came apart into "@permadeath.c" and "om". + + `break-word` and not `anywhere`: both break a word too long for its column, + and only `anywhere` also breaks one that would have fitted after a wrap. */ .profile-name { margin: 0; - font-size: clamp(1.6rem, 6cqw, 2.6rem); + font-size: clamp(1.35rem, 11cqw, 2.6rem); line-height: 1.05; - overflow-wrap: anywhere; + overflow-wrap: break-word; } .profile-links { @@ -3118,14 +3145,25 @@ footer .debug { color: var(--muted); } -/* Phone: the picture goes above the name rather than beside it, because a - handle in a column 4rem wide breaks into a stack of syllables. */ -@media (max-width: 34rem) { +/* Narrow: the picture goes above the name rather than beside it, because a + handle in the column that is left breaks into a stack of syllables. + + 46rem rather than a phone's width: what runs out is not the window, it is + the column beside a 8.5rem picture, and a long handle runs out of that well + before anything else on the page is in trouble. */ +@media (max-width: 46rem) { .profile-head { flex-direction: column-reverse; align-items: stretch; } + /* The plate is what the ticks are pinned to, so it has to stay the size of + the picture: stretched across the column, they end up marking two corners + of the page instead of two corners of a portrait. */ + .profile-plate { + align-self: flex-start; + } + .profile-face { width: 6.5rem; height: 6.5rem;