styles: design tokens and self-hosted IBM Plex fonts

This commit is contained in:
Sergei Poljanski 2026-07-16 20:01:25 +04:00
commit 89700368ef
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
7 changed files with 236 additions and 88 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,7 +1,87 @@
/* Self-hosted fonts (no CDN). Latin subsets; Georgian falls back to the
vendored Noto, downloaded only when Georgian glyphs are on the page. */
@font-face {
font-family: 'IBM Plex Sans';
src: url('/fonts/ibm-plex-sans-latin-400-normal.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'IBM Plex Sans';
src: url('/fonts/ibm-plex-sans-latin-400-italic.woff2') format('woff2');
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'IBM Plex Sans';
src: url('/fonts/ibm-plex-sans-latin-600-normal.woff2') format('woff2');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'IBM Plex Sans';
src: url('/fonts/ibm-plex-sans-latin-700-normal.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'IBM Plex Mono';
src: url('/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Noto Sans Georgian';
src: url('/fonts/NotoSansGeorgian-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+10A0-10FF, U+1C90-1CBF, U+2D00-2D2F;
}
/* Design tokens — shared palette with blog.asxp.io */
:root {
--bg: #121212;
--surface: #1A1A1A;
--surface-alt: #222222;
--surface-hover: #333333;
--border-subtle: #1E1E1E;
--border: #2A2A2A;
--border-strong: #3A3A3A;
--text: #AAAAAA;
--text-bright: #EEEEEE;
--text-strong: #DDDDDD;
--text-soft: #CCCCCC;
--text-link: #BBBBBB;
--text-dim: #999999;
--text-dimmer: #888888;
--text-faint: #777777;
--text-muted: #666666;
--text-ghost: #555555;
--text-hover: #FFFFFF;
--link-underline: #444444;
--danger: #C97070;
--danger-border: #4A1F1F;
--danger-bg: #2A1414;
--pending: #C9A86A;
--pending-border: #4A3E1F;
--pending-bg: #2A2414;
--paid: #7AB97A;
--paid-border: #234A23;
--paid-bg: #142A14;
--font-sans: 'IBM Plex Sans', 'Noto Sans Georgian', sans-serif;
--font-mono: 'IBM Plex Mono', monospace;
}
body { body {
background-color: #121212; background-color: var(--bg);
color: #AAAAAA; color: var(--text);
font-family: 'Open Sans', sans-serif; font-family: var(--font-sans);
margin: 0; margin: 0;
line-height: 1.5; line-height: 1.5;
} }
@ -10,6 +90,38 @@ main {
margin: 0 auto; margin: 0 auto;
padding: 40px 20px 80px; padding: 40px 20px 80px;
} }
.site-header {
display: flex;
justify-content: space-between;
align-items: baseline;
border-bottom: 1px solid var(--border);
padding-bottom: 12px;
margin-bottom: 36px;
}
.site-title {
font-family: var(--font-mono);
font-size: 1.1rem;
color: var(--text-bright);
border-bottom: none;
}
.site-header nav a {
color: var(--text-faint);
border-bottom: none;
margin-left: 18px;
font-size: 0.9rem;
}
.site-header nav a:hover,
.site-header nav a.active,
.site-title:hover {
color: var(--text-bright);
border-bottom: none;
}
.home-intro {
max-width: 480px;
margin: 0 auto;
text-align: center;
color: var(--text);
}
.header { .header {
text-align: center; text-align: center;
margin-bottom: 40px; margin-bottom: 40px;
@ -24,19 +136,19 @@ main {
.header h1 { .header h1 {
font-size: 1.8rem; font-size: 1.8rem;
font-weight: 600; font-weight: 600;
color: #EEEEEE; color: var(--text-bright);
margin: 0; margin: 0;
letter-spacing: -0.01em; letter-spacing: -0.01em;
} }
.header .tagline { .header .tagline {
font-size: 1rem; font-size: 1rem;
color: #999999; color: var(--text-dim);
margin: 8px 0 0; margin: 8px 0 0;
} }
.header .ka { .header .ka {
display: block; display: block;
font-size: 0.85rem; font-size: 0.85rem;
color: #666666; color: var(--text-muted);
margin-top: 6px; margin-top: 6px;
} }
.section { .section {
@ -45,10 +157,10 @@ main {
.section h2 { .section h2 {
font-size: 1rem; font-size: 1rem;
font-weight: 600; font-weight: 600;
color: #DDDDDD; color: var(--text-strong);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
border-bottom: 1px solid #2A2A2A; border-bottom: 1px solid var(--border);
padding-bottom: 6px; padding-bottom: 6px;
margin: 0 0 16px; margin: 0 0 16px;
} }
@ -57,8 +169,11 @@ ul.services {
padding: 0; padding: 0;
margin: 0; margin: 0;
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); /* Column count derives from available width no breakpoint needed,
gap: 8px 24px; behaves at any zoom level. */
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 10px 24px;
align-items: start;
} }
ul.services li { ul.services li {
padding-left: 14px; padding-left: 14px;
@ -68,7 +183,14 @@ ul.services li::before {
content: ''; content: '';
position: absolute; position: absolute;
left: 0; left: 0;
color: #555555; color: var(--text-ghost);
}
.svc-tools {
display: block;
font-family: var(--font-mono);
font-size: 0.8rem;
color: var(--text-muted);
margin-top: 2px;
} }
dl.kv { dl.kv {
display: grid; display: grid;
@ -77,29 +199,29 @@ dl.kv {
margin: 0; margin: 0;
} }
dl.kv dt { dl.kv dt {
color: #777777; color: var(--text-faint);
font-size: 0.9rem; font-size: 0.9rem;
} }
dl.kv dd { dl.kv dd {
margin: 0; margin: 0;
color: #CCCCCC; color: var(--text-soft);
} }
dl.kv dd.mono, dl.kv dd.mono,
.mono { .mono {
font-family: 'Hack', monospace; font-family: var(--font-mono);
font-size: 0.92rem; font-size: 0.92rem;
} }
.ka-note { .ka-note {
color: #666666; color: var(--text-muted);
font-size: 0.85rem; font-size: 0.85rem;
margin-top: 4px; margin-top: 4px;
} }
pre { pre {
position: relative; position: relative;
background: #222222; background: var(--surface-alt);
padding: 10px; padding: 10px;
font-size: 14px; font-size: 14px;
font-family: 'Hack', monospace; font-family: var(--font-mono);
word-wrap: break-word; word-wrap: break-word;
white-space: pre-wrap; white-space: pre-wrap;
border: 1px solid #020202; border: 1px solid #020202;
@ -119,20 +241,20 @@ pre {
color: #000; color: #000;
} }
a { a {
color: #BBBBBB; color: var(--text-link);
text-decoration: none; text-decoration: none;
border-bottom: 1px dotted #444444; border-bottom: 1px dotted var(--link-underline);
} }
a:hover { a:hover {
color: #FFFFFF; color: var(--text-hover);
border-bottom-color: #888888; border-bottom-color: var(--text-dimmer);
} }
.footer { .footer {
text-align: center; text-align: center;
color: #555555; color: var(--text-ghost);
font-size: 0.8rem; font-size: 0.8rem;
padding: 24px 20px; padding: 24px 20px;
border-top: 1px solid #1E1E1E; border-top: 1px solid var(--border-subtle);
} }
.footer-line { .footer-line {
margin-bottom: 12px; margin-bottom: 12px;
@ -144,12 +266,12 @@ a:hover {
align-items: center; align-items: center;
} }
.footer-links a { .footer-links a {
color: #555555; color: var(--text-ghost);
border-bottom: none; border-bottom: none;
line-height: 0; line-height: 0;
} }
.footer-links a:hover { .footer-links a:hover {
color: #FFFFFF; color: var(--text-hover);
} }
.footer-links svg { .footer-links svg {
display: block; display: block;
@ -167,16 +289,21 @@ a:hover {
overflow: hidden; overflow: hidden;
} }
.contact-form .field { .contact-form .field {
margin-bottom: 14px; margin-bottom: 10px;
}
.contact-form .form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0 14px;
} }
.contact-form label { .contact-form label {
display: block; display: block;
color: #888888; color: var(--text-dimmer);
font-size: 0.85rem; font-size: 0.8rem;
margin-bottom: 4px; margin-bottom: 3px;
} }
.contact-form .optional { .contact-form .optional {
color: #555555; color: var(--text-ghost);
font-size: 0.8rem; font-size: 0.8rem;
} }
.contact-form input[type="text"], .contact-form input[type="text"],
@ -184,29 +311,29 @@ a:hover {
.contact-form textarea { .contact-form textarea {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
background: #1A1A1A; background: var(--surface);
color: #DDDDDD; color: var(--text-strong);
border: 1px solid #2A2A2A; border: 1px solid var(--border);
border-radius: 3px; border-radius: 3px;
padding: 8px 10px; padding: 8px 10px;
font-family: inherit; font-family: inherit;
font-size: 0.95rem; font-size: 0.95rem;
} }
.contact-form textarea { .contact-form textarea {
font-family: 'Hack', monospace; font-family: var(--font-mono);
font-size: 0.9rem; font-size: 0.9rem;
resize: vertical; resize: vertical;
} }
.contact-form input:focus, .contact-form input:focus,
.contact-form textarea:focus { .contact-form textarea:focus {
outline: none; outline: none;
border-color: #555555; border-color: var(--text-ghost);
background: #1E1E1E; background: var(--border-subtle);
} }
.contact-form button { .contact-form button {
background: #2A2A2A; background: var(--border);
color: #DDDDDD; color: var(--text-strong);
border: 1px solid #3A3A3A; border: 1px solid var(--border-strong);
border-radius: 3px; border-radius: 3px;
padding: 8px 20px; padding: 8px 20px;
font-family: inherit; font-family: inherit;
@ -214,51 +341,72 @@ a:hover {
cursor: pointer; cursor: pointer;
} }
.contact-form button:hover { .contact-form button:hover {
background: #333333; background: var(--surface-hover);
border-color: #555555; border-color: var(--text-ghost);
} }
.form-error { .form-error {
display: block; display: block;
color: #C97070; color: var(--danger);
font-size: 0.85rem; font-size: 0.85rem;
margin-top: 4px; margin-top: 4px;
} }
.form-error-base { .form-error-base {
background: #2A1414; background: var(--danger-bg);
border: 1px solid #4A1F1F; border: 1px solid var(--danger-border);
padding: 10px; padding: 10px;
border-radius: 3px; border-radius: 3px;
margin-bottom: 16px; margin-bottom: 16px;
} }
.contact-direct { .contact-direct {
margin-top: 16px; margin-top: 18px;
padding-top: 16px; padding-top: 14px;
border-top: 1px dashed #2A2A2A; border-top: 1px dashed var(--border);
}
/* Keys */
.key-block {
margin-bottom: 20px;
}
.key-head {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 4px;
}
.key-label {
font-family: var(--font-mono);
font-size: 0.8rem;
color: var(--text-faint);
letter-spacing: 0.08em;
}
.key-file {
font-family: var(--font-mono);
font-size: 0.85rem;
} }
/* Demoted Legal section — visible but quiet */ /* Demoted Legal section — visible but quiet */
.section.legal { .section.legal {
margin-top: 56px; margin-top: 56px;
color: #888888; color: var(--text-dimmer);
font-size: 0.9rem; font-size: 0.9rem;
} }
.section.legal h2 { .section.legal h2 {
font-size: 0.85rem; font-size: 0.85rem;
color: #888888; color: var(--text-dimmer);
border-bottom-color: #1E1E1E; border-bottom-color: var(--border-subtle);
text-transform: none; text-transform: none;
letter-spacing: 0.04em; letter-spacing: 0.04em;
} }
.section.legal .legal-intro { .section.legal .legal-intro {
margin: 0 0 14px; margin: 0 0 14px;
color: #777777; color: var(--text-faint);
} }
.section.legal dl.kv dt { .section.legal dl.kv dt {
color: #666666; color: var(--text-muted);
font-size: 0.85rem; font-size: 0.85rem;
} }
.section.legal dl.kv dd { .section.legal dl.kv dd {
color: #999999; color: var(--text-dim);
font-size: 0.9rem; font-size: 0.9rem;
} }
@ -272,10 +420,10 @@ a:hover {
.invoice-list td { .invoice-list td {
text-align: left; text-align: left;
padding: 8px 10px; padding: 8px 10px;
border-bottom: 1px solid #1E1E1E; border-bottom: 1px solid var(--border-subtle);
} }
.invoice-list th { .invoice-list th {
color: #777777; color: var(--text-faint);
font-weight: 600; font-weight: 600;
font-size: 0.78rem; font-size: 0.78rem;
text-transform: uppercase; text-transform: uppercase;
@ -298,14 +446,14 @@ a:hover {
border: 1px solid; border: 1px solid;
} }
.badge-pending { .badge-pending {
color: #C9A86A; color: var(--pending);
border-color: #4A3E1F; border-color: var(--pending-border);
background: #2A2414; background: var(--pending-bg);
} }
.badge-paid { .badge-paid {
color: #7AB97A; color: var(--paid);
border-color: #234A23; border-color: var(--paid-border);
background: #142A14; background: var(--paid-bg);
} }
.invoice-grid { .invoice-grid {
display: grid; display: grid;
@ -324,7 +472,7 @@ a:hover {
vertical-align: top; vertical-align: top;
} }
.items-table th { .items-table th {
color: #777777; color: var(--text-faint);
font-weight: 600; font-weight: 600;
font-size: 0.78rem; font-size: 0.78rem;
text-transform: uppercase; text-transform: uppercase;
@ -337,9 +485,9 @@ a:hover {
.items-table input { .items-table input {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
background: #1A1A1A; background: var(--surface);
color: #DDDDDD; color: var(--text-strong);
border: 1px solid #2A2A2A; border: 1px solid var(--border);
border-radius: 3px; border-radius: 3px;
padding: 6px 8px; padding: 6px 8px;
font-family: inherit; font-family: inherit;
@ -347,7 +495,7 @@ a:hover {
} }
.items-table td.num input { .items-table td.num input {
text-align: right; text-align: right;
font-family: 'Hack', monospace; font-family: var(--font-mono);
} }
.items-table td.actions { .items-table td.actions {
width: 32px; width: 32px;
@ -355,21 +503,21 @@ a:hover {
} }
.items-table .remove-row { .items-table .remove-row {
background: transparent; background: transparent;
border: 1px solid #2A2A2A; border: 1px solid var(--border);
color: #777777; color: var(--text-faint);
border-radius: 3px; border-radius: 3px;
padding: 4px 8px; padding: 4px 8px;
cursor: pointer; cursor: pointer;
line-height: 1; line-height: 1;
} }
.items-table .remove-row:hover { .items-table .remove-row:hover {
color: #C97070; color: var(--danger);
border-color: #4A1F1F; border-color: var(--danger-border);
} }
.link-button { .link-button {
background: transparent; background: transparent;
border: 1px dashed #2A2A2A; border: 1px dashed var(--border);
color: #888888; color: var(--text-dimmer);
padding: 6px 12px; padding: 6px 12px;
border-radius: 3px; border-radius: 3px;
cursor: pointer; cursor: pointer;
@ -377,15 +525,15 @@ a:hover {
margin-bottom: 18px; margin-bottom: 18px;
} }
.link-button:hover { .link-button:hover {
color: #DDDDDD; color: var(--text-strong);
border-color: #555555; border-color: var(--text-ghost);
} }
.invoice-form select { .invoice-form select {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
background: #1A1A1A; background: var(--surface);
color: #DDDDDD; color: var(--text-strong);
border: 1px solid #2A2A2A; border: 1px solid var(--border);
border-radius: 3px; border-radius: 3px;
padding: 8px 10px; padding: 8px 10px;
font-family: inherit; font-family: inherit;
@ -394,33 +542,33 @@ a:hover {
.invoice-form input[type="date"] { .invoice-form input[type="date"] {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
background: #1A1A1A; background: var(--surface);
color: #DDDDDD; color: var(--text-strong);
border: 1px solid #2A2A2A; border: 1px solid var(--border);
border-radius: 3px; border-radius: 3px;
padding: 8px 10px; padding: 8px 10px;
font-family: 'Hack', monospace; font-family: var(--font-mono);
font-size: 0.92rem; font-size: 0.92rem;
color-scheme: dark; color-scheme: dark;
} }
.download-button { .download-button {
display: inline-block; display: inline-block;
background: #2A2A2A; background: var(--border);
color: #DDDDDD; color: var(--text-strong);
border: 1px solid #3A3A3A; border: 1px solid var(--border-strong);
border-radius: 3px; border-radius: 3px;
padding: 12px 32px; padding: 12px 32px;
font-size: 1rem; font-size: 1rem;
text-decoration: none; text-decoration: none;
} }
.download-button:hover { .download-button:hover {
background: #333333; background: var(--surface-hover);
border-color: #555555; border-color: var(--text-ghost);
color: #FFFFFF; color: var(--text-hover);
} }
@media (max-width: 560px) { @media (max-width: 560px) {
ul.services { .contact-form .form-row {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
dl.kv { dl.kv {