feat: introduce mathematical type scale with single-source-of-truth typography tokens

Define a major-third (1.25) type scale as CSS custom properties in the tokens
layer (--text-2xs through --text-5xl), along with line-height (--leading-*),
font-weight (--font-*), and letter-spacing (--tracking-*) tokens. Migrate all
28 core CSS files from ad-hoc values to token references with clamp()-based
responsive scaling for headings. Add TypographyTokenContractTest to enforce
token-only usage via grep-based assertions.

Task run: UI-TYPOGRAPHY-SCALE-001

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-22 15:47:55 +01:00
parent cf8c59d3f8
commit e145b7d089
30 changed files with 390 additions and 146 deletions

View File

@@ -38,9 +38,9 @@
align-items: center;
gap: 0.45rem;
padding: 0.3rem 0.65rem;
font-size: 0.78rem;
line-height: 1.15;
font-weight: 500;
font-size: var(--text-xs);
line-height: var(--leading-tight);
font-weight: var(--font-medium);
color: var(--app-form-element-color);
--app-background-color: var(--app-form-element-background-color);
--app-border-color: var(--app-form-element-border-color);
@@ -76,7 +76,7 @@
width: 1rem;
height: 1rem;
border-radius: 999px;
font-size: 0.58rem;
font-size: var(--text-2xs);
background: var(--app-muted-border-color);
}

View File

@@ -7,9 +7,9 @@
gap: 0.35em;
padding: 0.15em 0.6em;
border-radius: 999px;
font-size: 0.85em;
font-weight: 400;
line-height: 1.2;
font-size: 0.85em; /* em-relative sizing — intentional, scales with parent */
font-weight: var(--font-regular);
line-height: var(--leading-tight);
border: 1px solid transparent;
white-space: nowrap;
}
@@ -26,12 +26,12 @@
align-items: center;
justify-content: center;
color: inherit;
line-height: 1;
font-size: 10px;
line-height: var(--leading-none);
font-size: 10px; /* icon-font metric — intentional px */
}
.badge .badge-copy-icon .bi {
font-size: 0.95em;
font-size: 0.95em; /* em-relative sizing — intentional, scales with parent */
}
.badge .badge-copy-icon .bi-check2 {

View File

@@ -14,17 +14,17 @@ img.brand-logo {
}
.brand-name {
line-height: 1;
font-weight: bold;
line-height: var(--leading-none);
font-weight: var(--font-bold);
color: var(--app-contrast);
}
.brand-info {
line-height: 1;
line-height: var(--leading-none);
}
.brand-slogan {
font-size: 0.85em;
font-size: 0.85em; /* em-relative sizing — intentional, scales with parent */
color: var(--app-muted-color);
}

View File

@@ -5,7 +5,7 @@
display: flex;
align-items: center;
gap: 3px;
font-size: 11px;
font-size: var(--text-xs);
}
.app-breadcrumb a {

View File

@@ -22,7 +22,7 @@
.app-dashboard-titlebar [role="button"] {
--app-button-padding-horizontal: 10px;
--app-button-padding-vertical: 6px;
font-size: 13px;
font-size: var(--text-sm);
margin: 0;
}
@@ -37,7 +37,7 @@
background: var(--app-muted-border-color);
width: 35px;
height: 29px;
font-size: 15px;
font-size: 15px; /* icon-font metric — intentional px */
border-radius: var(--app-border-radius);
display: inline-flex;
align-items: center;
@@ -49,7 +49,7 @@
display: flex;
align-items: center;
gap: 7px;
line-height: 1;
line-height: var(--leading-none);
}
.app-dashboard-titlebar h1 a:hover i {

View File

@@ -12,8 +12,8 @@
details.app-details-card > summary {
margin: 0;
padding: calc(var(--app-spacing) * 0.75) var(--app-spacing);
font-size: 0.85rem;
line-height: 1.25;
font-size: var(--text-sm);
line-height: var(--leading-tight);
text-transform: none;
background: var(--app-card-sectioning-background-color);
display: flex;

View File

@@ -22,13 +22,13 @@
.app-details-titlebar [role="button"] {
--app-button-padding-horizontal: 10px;
--app-button-padding-vertical: 6px;
font-size: 13px;
font-size: var(--text-sm);
margin: 0;
}
.app-details-titlebar button i,
.app-details-titlebar [role="button"] i {
font-size: 10px;
font-size: 10px; /* icon-font metric — intentional px */
}
.app-details-titlebar-actions {
@@ -47,7 +47,7 @@
background: var(--app-background-color);
width: 35px;
height: 29px;
font-size: 15px;
font-size: 15px; /* icon-font metric — intentional px */
border-radius: var(--app-border-radius);
display: inline-flex;
align-items: center;
@@ -62,7 +62,7 @@
display: flex;
align-items: center;
gap: 7px;
line-height: 1;
line-height: var(--leading-none);
}
.app-details-titlebar details.dropdown {
margin-bottom: 0;

View File

@@ -27,7 +27,7 @@
.app-details-validation-summary-title {
margin: 0;
font-weight: 600;
font-weight: var(--font-semibold);
color: var(--app-validation-summary-title-color);
}

View File

@@ -44,13 +44,13 @@
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-weight: var(--font-semibold);
color: var(--app-muted-color);
}
.user-avatar-placeholder,
.entity-avatar-placeholder {
font-size: 1.5rem;
font-size: var(--text-2xl);
}
.user-avatar-image {

View File

@@ -41,15 +41,15 @@
.app-empty-state-message {
margin: 0;
color: var(--app-empty-hint);
font-size: 12px;
line-height: 1.4;
font-size: var(--text-xs);
line-height: var(--leading-snug);
}
.app-empty-state-hint {
margin: 0;
color: var(--app-empty-hint);
font-size: 0.85rem;
line-height: 1.3;
font-size: var(--text-sm);
line-height: var(--leading-snug);
opacity: 0.75;
}

View File

@@ -55,8 +55,8 @@
.app-filter-drawer-header h2 {
margin: 0;
font-size: 0.8125rem;
line-height: 1.2;
font-size: var(--text-sm);
line-height: var(--leading-tight);
}
.app-filter-drawer-header .icon-button {
@@ -111,7 +111,7 @@
.app-filter-drawer-body .app-list-toolbar .app-field > span,
.app-filter-drawer-body .app-list-toolbar > label > span {
margin: 0 !important;
line-height: 1.2;
line-height: var(--leading-tight);
}
.app-filter-drawer-body .app-list-toolbar input:not([type="hidden"]),
@@ -153,7 +153,7 @@
.app-list-toolbar
.multi-select
.multi-select-header-option {
line-height: 1.2;
line-height: var(--leading-tight);
}
.app-filter-drawer-body #address-book-custom-filters {

View File

@@ -60,8 +60,8 @@
position: relative;
overflow: hidden;
color: var(--app-notice-border-color);
font-size: 0.875rem;
line-height: 1.4;
font-size: var(--text-sm);
line-height: var(--leading-snug);
pointer-events: auto;
margin: 0;
animation: toast-slide-in 250ms ease-out;
@@ -159,7 +159,7 @@
opacity: 0.6;
cursor: pointer;
padding: 2px 4px;
line-height: 1;
line-height: var(--leading-none);
flex-shrink: 0;
}

View File

@@ -28,13 +28,13 @@
.app-form-info-tile-label {
display: block;
color: var(--app-muted-color);
line-height: 1.3;
line-height: var(--leading-snug);
}
.app-form-info-tile-value {
display: block;
color: var(--app-contrast);
line-height: 1.35;
line-height: var(--leading-snug);
}
.app-form-info-tile--success {

View File

@@ -1,7 +1,7 @@
@layer components {
/* Form element enhancements — validation hints, color inputs, checkbox/radio labels, disabled states. */
.form-hint {
font-size: small;
font-size: var(--text-sm);
}
ul.form-hint-list {
@@ -25,19 +25,19 @@
content: "\F26B";
font-family: "Bootstrap-icons";
margin-left: 4px;
font-size: 10px;
font-size: 10px; /* icon-font metric — intentional px */
}
ul.form-hint-list li.is-invalid:after {
content: "\F33A";
font-family: "Bootstrap-icons";
margin-left: 4px;
font-size: 10px;
font-size: 10px; /* icon-font metric — intentional px */
}
label:has([type="checkbox"], [type="radio"]) {
display: flex;
line-height: 1;
line-height: var(--leading-none);
align-items: center;
}

View File

@@ -14,7 +14,7 @@
padding: 5px 10px 5px 10px;
color: var(--list-tabs-muted);
cursor: pointer;
font-weight: 500;
font-weight: var(--font-medium);
border-bottom: 2px solid transparent;
text-decoration: none;
}

View File

@@ -22,7 +22,7 @@
.app-list-titlebar [role="button"] {
--app-button-padding-horizontal: 10px;
--app-button-padding-vertical: 6px;
font-size: 13px;
font-size: var(--text-sm);
margin: 0;
}
@@ -37,7 +37,7 @@
background: var(--app-muted-border-color);
width: 35px;
height: 35px;
font-size: 16px;
font-size: 16px; /* icon-font metric — intentional px */
border-radius: var(--app-border-radius);
display: inline-flex;
align-items: center;

View File

@@ -13,7 +13,7 @@
width: auto !important;
--app-form-element-spacing-horizontal: 10px;
--app-form-element-spacing-vertical: 6px;
font-size: 13px !important;
font-size: var(--text-sm) !important;
height: auto !important;
}
.app-list-toolbar > * > * {
@@ -21,7 +21,7 @@
width: auto !important;
--app-form-element-spacing-horizontal: 10px;
--app-form-element-spacing-vertical: 6px;
font-size: 13px !important;
font-size: var(--text-sm) !important;
height: auto !important;
}
.app-list-toolbar > * > * > * {
@@ -29,7 +29,7 @@
width: auto !important;
--app-form-element-spacing-horizontal: 10px;
--app-form-element-spacing-vertical: 6px;
font-size: 13px !important;
font-size: var(--text-sm) !important;
height: auto !important;
}
@@ -55,7 +55,7 @@
.app-list-toolbar > label > span {
display: block;
font-size: 11px !important;
font-size: var(--text-xs) !important;
}
.app-list-toolbar .app-grid-page-size select {
@@ -76,7 +76,7 @@
.multi-select
.multi-select-header
.multi-select-header-placeholder {
font-size: 13px;
font-size: var(--text-sm);
}
.app-list-toolbar .multi-select .multi-select-header,
@@ -95,6 +95,6 @@
border: 0 !important;
padding: 0 !important;
padding-left: 3px !important;
font-size: 11px !important;
font-size: var(--text-xs) !important;
}
}

View File

@@ -15,8 +15,8 @@
border-radius: 6px;
background: var(--app-card-background-color);
color: var(--app-muted-color);
font-size: 0.75rem;
line-height: 1;
font-size: var(--text-xs);
line-height: var(--leading-none);
padding: 0.2rem 0.4rem;
pointer-events: none;
}
@@ -28,13 +28,13 @@
border-radius: var(--app-border-radius);
text-align: center;
color: var(--app-muted-color);
font-size: 0.9rem;
font-size: var(--text-sm);
cursor: text;
}
.app-search-empty-state .bi-search {
display: inline-block;
font-size: 1.25rem;
font-size: var(--text-xl);
margin-bottom: 0.5rem;
color: var(--app-color);
}
@@ -57,7 +57,7 @@ ul.app-search-results > li > a {
}
ul.app-search-results .badge {
font-size: 10px;
font-size: 10px; /* icon-font metric — intentional px */
padding: 1px;
min-width: 18px;
text-align: center;
@@ -73,7 +73,7 @@ ul.app-search-results .badge {
ul.app-search-preview {
position: relative;
font-size: 11px;
font-size: var(--text-xs);
padding: 0 0 0 0;
margin: 0;
opacity: 0.75;
@@ -120,7 +120,7 @@ input#side-search {
--app-form-element-spacing-horizontal: 10px;
--app-form-element-spacing-vertical: 6px;
height: auto;
font-size: 13px;
font-size: var(--text-sm);
padding-right: 3rem;
margin-bottom:0;
}
@@ -160,18 +160,18 @@ ul.app-search-preview:has(li) {
.search-result-title {
font-weight: 600;
font-weight: var(--font-semibold);
text-decoration: none;
}
.search-result-desc {
margin: 0;
color: var(--app-muted-color);
font-size: small;
font-size: var(--text-sm);
}
.search-result-type {
color: var(--app-muted-color);
font-weight: 600;
font-weight: var(--font-semibold);
}
}

View File

@@ -40,8 +40,8 @@
border-radius: var(--app-border-radius);
background-color: transparent;
color: var(--app-secondary);
font-size: 13px;
line-height: 1;
font-size: var(--text-sm);
line-height: var(--leading-none);
cursor: pointer;
z-index: 1;
margin-block: auto;

View File

@@ -67,14 +67,14 @@
border-radius: 10px;
background: var(--tile-icon-bg);
color: var(--tile-icon-color);
font-size: 1.1rem;
font-size: var(--text-lg);
}
.app-tile-count {
position: absolute;
top: calc(var(--app-spacing) * 1);
right: calc(var(--app-spacing) * 1);
font-weight: 700;
font-weight: var(--font-bold);
color: var(--tile-count-color);
}
@@ -93,7 +93,7 @@
right: calc(var(--app-spacing) * 1);
bottom: calc(var(--app-spacing) * 1);
color: var(--tile-link-color);
font-size: 0.9rem;
font-size: var(--text-sm);
}
.app-tile.is-small {
@@ -106,7 +106,7 @@
width: 25px;
height: 25px;
border-radius: 6px;
font-size: 12px;
font-size: 12px; /* icon-font metric — intentional px */
margin-right: 10px;
}
@@ -121,14 +121,14 @@
}
.app-tile.is-small .app-tile-label {
margin-top: 0;
font-weight: 400;
font-weight: var(--font-regular);
}
.app-stats-table-header {
border-bottom: 1px solid var(--app-border);
padding: 4px 10px 4px 10px;
text-transform: uppercase;
font-size: 13px;
font-size: var(--text-sm);
letter-spacing: 0.4px;
background: var(--app-blockquote-background-color);
}

View File

@@ -22,7 +22,7 @@
border: 1px solid var(--tooltip-border);
border-radius: var(--tooltip-radius);
box-shadow: var(--tooltip-shadow);
font-size: 0.75rem;
font-size: var(--text-xs);
padding: 0.35rem 0.6rem;
white-space: nowrap;
}