fix: unify typography and review interactions
verify-and-publish / gate (push) Successful in 5m35s
verify-and-publish / publish (push) Has been skipped

This commit is contained in:
Marcos Paulo
2026-09-06 16:34:39 +00:00
parent ef5e8e8b42
commit 61de2f6270
9 changed files with 196 additions and 23 deletions
+8
View File
@@ -329,6 +329,14 @@ if (
) )
) )
throw new Error('missing rules responsive contract'); throw new Error('missing rules responsive contract');
if (
![
'body{min-width:320px;margin:0;color:var(--ink);background:var(--paper);font-family:var(--font-sans)}',
'max-width:75ch;font-size:var(--step-24)',
'max-width:75ch;font-size:var(--step-20)',
].every((token) => builtCss.includes(token))
)
throw new Error('rules page lost its global font or 4K prose scale');
if ( if (
!['font:700 var(--step-18) var(--font-mono)', 'font:500 var(--step-48) var(--font-mono)'].every( !['font:700 var(--step-18) var(--font-mono)', 'font:500 var(--step-48) var(--font-mono)'].every(
(token) => builtCss.includes(token), (token) => builtCss.includes(token),
+1 -1
View File
@@ -47,7 +47,7 @@ const { navLabel = 'Chapter navigation' } = Astro.props;
color: var(--ink); color: var(--ink);
border: 1px solid var(--ink); border: 1px solid var(--ink);
text-decoration: none; text-decoration: none;
font: var(--step-0) monospace; font: var(--step-0) var(--font-mono);
text-transform: uppercase; text-transform: uppercase;
} }
+1 -1
View File
@@ -34,7 +34,7 @@ const { id } = Astro.props;
gap: 20px; gap: 20px;
padding: 24px 0; padding: 24px 0;
border-bottom: 1px solid var(--line); border-bottom: 1px solid var(--line);
font: 700 var(--step-0) monospace; font: 700 var(--step-0) var(--font-mono);
letter-spacing: 0.08em; letter-spacing: 0.08em;
text-transform: uppercase; text-transform: uppercase;
} }
+54 -3
View File
@@ -498,15 +498,15 @@ fix(api): scope session query</code></pre>
.rules-root :global(*) { .rules-root :global(*) {
box-sizing: border-box; box-sizing: border-box;
} }
.rules-root :global(html) { :global(html) {
scroll-behavior: smooth; scroll-behavior: smooth;
} }
.rules-root :global(body) { :global(body) {
min-width: 320px; min-width: 320px;
margin: 0; margin: 0;
color: var(--ink); color: var(--ink);
background: var(--paper); background: var(--paper);
font-family: Manrope, Arial, sans-serif; font-family: var(--font-sans);
} }
.progress { .progress {
@@ -723,6 +723,10 @@ fix(api): scope session query</code></pre>
background: transparent; background: transparent;
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
transition:
color 180ms cubic-bezier(0.2, 0, 0, 1),
background-color 180ms cubic-bezier(0.2, 0, 0, 1),
transform 180ms cubic-bezier(0.2, 0, 0, 1);
} }
.pipeline button span { .pipeline button span {
color: var(--accent); color: var(--accent);
@@ -746,6 +750,9 @@ fix(api): scope session query</code></pre>
background: var(--blue); background: var(--blue);
box-shadow: inset 0 -6px var(--gold); box-shadow: inset 0 -6px var(--gold);
} }
.pipeline button:hover {
transform: translateY(-2px);
}
.pipeline button.active span, .pipeline button.active span,
.pipeline button.active small { .pipeline button.active small {
color: var(--gold); color: var(--gold);
@@ -765,6 +772,11 @@ fix(api): scope session query</code></pre>
color: var(--paper); color: var(--paper);
background: var(--deep); background: var(--deep);
} }
.stage-detail > *,
.skill-detail > * {
/* purpose: make a replaced detail panel legible as a state change */
animation: rules-detail-in 200ms cubic-bezier(0.2, 0, 0, 1) both;
}
.stage-number { .stage-number {
color: var(--white-14); color: var(--white-14);
font: font:
@@ -849,6 +861,10 @@ fix(api): scope session query</code></pre>
background: var(--paper); background: var(--paper);
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
transition:
color 180ms cubic-bezier(0.2, 0, 0, 1),
background-color 180ms cubic-bezier(0.2, 0, 0, 1),
transform 180ms cubic-bezier(0.2, 0, 0, 1);
} }
.skill-list button strong { .skill-list button strong {
font: font:
@@ -864,6 +880,20 @@ fix(api): scope session query</code></pre>
background: var(--accent); background: var(--accent);
box-shadow: inset 6px 0 var(--gold); box-shadow: inset 6px 0 var(--gold);
} }
.skill-list button:hover {
transform: translateX(3px);
}
@keyframes rules-detail-in {
from {
opacity: 0.01;
transform: translateY(6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.skill-list button.active small { .skill-list button.active small {
color: var(--accent-paper-active); color: var(--accent-paper-active);
} }
@@ -1056,6 +1086,19 @@ fix(api): scope session query</code></pre>
.hero h1 { .hero h1 {
font-size: clamp(150px, 7vw, 220px); font-size: clamp(150px, 7vw, 220px);
} }
.hero-foot > p {
max-width: 75ch;
font-size: var(--step-24);
}
.intro > p {
max-width: 75ch;
font-size: var(--step-20);
}
.stage-detail p,
.skill-detail p {
max-width: 75ch;
font-size: var(--step-18);
}
.pipeline button { .pipeline button {
min-height: 170px; min-height: 170px;
} }
@@ -1196,5 +1239,13 @@ fix(api): scope session query</code></pre>
.progress span { .progress span {
transition: none; transition: none;
} }
.pipeline button,
.skill-list button {
transition: none;
}
.stage-detail > *,
.skill-detail > * {
animation: none;
}
} }
</style> </style>
@@ -148,9 +148,7 @@ const packageFiles: PackageFile[] = [
.package-preview > span { .package-preview > span {
margin: 0 0 14px; margin: 0 0 14px;
color: var(--gold); color: var(--gold);
font: font: 700 var(--step-0) / 1.35 var(--font-mono);
700 var(--step-0) / 1.35 ui-monospace,
monospace;
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
@@ -188,16 +186,12 @@ const packageFiles: PackageFile[] = [
.package-tree code { .package-tree code {
min-width: 0; min-width: 0;
overflow-wrap: anywhere; overflow-wrap: anywhere;
font: font: 700 var(--step-13) / 1.4 var(--font-mono);
700 13px / 1.4 ui-monospace,
monospace;
} }
.package-tree small { .package-tree small {
color: var(--muted); color: var(--muted);
font: font: var(--step-0) / 1.25 var(--font-sans);
11px / 1.25 Arial,
sans-serif;
text-align: right; text-align: right;
} }
@@ -229,9 +223,7 @@ const packageFiles: PackageFile[] = [
border: 1px solid var(--muted); border: 1px solid var(--muted);
background: var(--deep); background: var(--deep);
color: var(--line); color: var(--line);
font: font: var(--step-12) / 1.55 var(--font-mono);
12px / 1.55 ui-monospace,
monospace;
} }
.package-preview.is-swapping { .package-preview.is-swapping {
+2
View File
@@ -11,6 +11,7 @@ const { title, description, lang = 'en' } = Astro.props;
// bundled CSS because the legacy stylesheets @import the same file, so there // bundled CSS because the legacy stylesheets @import the same file, so there
// is exactly one copy of the faces. See public/fonts/fonts.css. // is exactly one copy of the faces. See public/fonts/fonts.css.
import tokensStylesheet from '../styles/tokens.css?url'; import tokensStylesheet from '../styles/tokens.css?url';
import baseStylesheet from '../styles/base.css?url';
const fonts = `${import.meta.env.BASE_URL}fonts/fonts.css`.replace('//', '/'); const fonts = `${import.meta.env.BASE_URL}fonts/fonts.css`.replace('//', '/');
--- ---
@@ -24,6 +25,7 @@ const fonts = `${import.meta.env.BASE_URL}fonts/fonts.css`.replace('//', '/');
<meta name="description" content={description} /> <meta name="description" content={description} />
<link rel="stylesheet" href={tokensStylesheet} /> <link rel="stylesheet" href={tokensStylesheet} />
<link rel="stylesheet" href={fonts} /> <link rel="stylesheet" href={fonts} />
<link rel="stylesheet" href={baseStylesheet} />
<slot name="styles" /> <slot name="styles" />
</head> </head>
<body> <body>
+2 -6
View File
@@ -84,9 +84,7 @@ const cards = data.cards ?? [];
padding: 12px 16px; padding: 12px 16px;
background: var(--ink); background: var(--ink);
color: var(--paper); color: var(--paper);
font: font: 700 var(--step-12) var(--font-mono);
700 var(--step-12) ui-monospace,
monospace;
letter-spacing: 0.06em; letter-spacing: 0.06em;
text-decoration: none; text-decoration: none;
text-transform: uppercase; text-transform: uppercase;
@@ -118,9 +116,7 @@ const cards = data.cards ?? [];
.landing-note span { .landing-note span {
color: var(--red); color: var(--red);
font: font: 700 var(--step-0) var(--font-mono);
700 var(--step-0) ui-monospace,
monospace;
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
+85
View File
@@ -155,3 +155,88 @@ const serializedCatalog = JSON.stringify(catalog).replace(/</g, '\\u003c');
import '../../legacy/skills-review/app.js'; import '../../legacy/skills-review/app.js';
</script> </script>
</BaseLayout> </BaseLayout>
<style is:global>
/* The catalog is a filing cabinet: its controls stay visible while only
the submission rows scroll. This prevents a long review set from making
the adjacent reading surface unusably tall. */
.catalog > aside {
position: sticky;
top: 24px;
display: flex;
align-self: start;
max-height: calc(100dvh - 48px);
overflow: hidden;
}
#skill-list {
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-color: var(--blue) var(--paper);
}
#skill-list button,
.file-tabs button,
.switch button,
.preview button {
transition:
color 180ms cubic-bezier(0.2, 0, 0, 1),
background-color 180ms cubic-bezier(0.2, 0, 0, 1),
transform 180ms cubic-bezier(0.2, 0, 0, 1);
}
#skill-list button:hover,
#skill-list button:focus-visible {
transform: translateX(3px);
}
.detail > * {
animation: review-detail-in 200ms cubic-bezier(0.2, 0, 0, 1) both;
}
.detail a,
.research a {
text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
}
.detail a:hover,
.research a:hover {
text-decoration-color: currentColor;
}
@keyframes review-detail-in {
from {
opacity: 0.01;
transform: translateY(6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 800px) {
.catalog > aside {
position: static;
max-height: none;
}
#skill-list {
max-height: 50dvh;
}
}
@media (prefers-reduced-motion: reduce) {
#skill-list button,
.file-tabs button,
.switch button,
.preview button {
transition: none;
}
.detail > * {
animation: none;
}
}
</style>
+39
View File
@@ -0,0 +1,39 @@
/* Typography belongs to the document, not browser defaults. Components may
* opt into the mono token for code and editorial labels. */
body {
font-family: var(--font-sans);
}
button,
input,
textarea,
select {
font: inherit;
}
code,
kbd,
pre,
samp {
font-family: var(--font-mono);
}
/* Text links read as editorial references. Page-level navigation can still
* deliberately remove the decoration. */
a {
text-decoration-thickness: 1px;
text-underline-offset: 0.18em;
transition:
color 180ms cubic-bezier(0.2, 0, 0, 1),
text-decoration-color 180ms cubic-bezier(0.2, 0, 0, 1);
}
a:hover {
text-decoration-color: currentcolor;
}
@media (prefers-reduced-motion: reduce) {
a {
transition: none;
}
}