diff --git a/DESIGN.md b/DESIGN.md index 8cad2e73..2ac85446 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -62,7 +62,8 @@ Surfaces: - `--bg-page`. Cream/ivory canvas, the body floor. The body uses a vertical gradient from `--bg-page-top` through `--bg-page` (at 24rem) to `--bg-page-end`, with a soft radial highlight in the top-left corner. - `--bg-paper`. Warm white for the content shell. -- `--bg-paper-strong`. Tinted paper for sponsor band, CTA backgrounds, static decoration. +- `--bg-paper-strong`. Tinted paper for CTA backgrounds and static decoration. +- `--sponsor-bg`. Deeper warm tint for the sponsor band only, so it reads as its own block between the hero and the table. - `--hero-bg-start` → `--hero-bg-mid` → `--hero-bg-end`. Dark earthy hero gradient. - `--footer-bg`. Dark warm charcoal footer, part of the same system. @@ -99,23 +100,32 @@ Pairing (do not swap): - **Display**: `Cormorant Garamond` (serif, 600 only). - **Body**: `Manrope` (sans, 400 / 600 / 700 / 800). +Cormorant Garamond sets headings and standalone names only, never running sentences, and never on the same line as Manrope. Its short x-height and thin strokes tire the eye across a paragraph, and next to Manrope on one baseline the two x-heights clash. Ledes and other multi-line copy use Manrope (`--text-2xl`); a display name with a description stacks the name above it, as in the sponsor band. + Scale: -| Role | Token | Size | Family | Weight | Notes | -| ---------------- | ----------------- | ----------------------------- | ------------------ | --------- | ---------------------------------------------- | -| Hero headline | (literal `clamp`) | `clamp(4.5rem, 11vw, 8.5rem)` | Cormorant Garamond | 600 | Magazine-cover scale, single use on the hero | -| Body large | `--text-lg` | `1.125rem` | Manrope | 400 | Content-heavy passages | -| Body | `--text-base` | `1rem` (16px) | Manrope | 400 | Body floor | -| Meta / secondary | `--text-sm` | `0.95rem` | Manrope | 400 / 600 | Meta rows, secondary copy | -| Caption / pill | `--text-xs` | `0.8rem` (12.8px) | Manrope | 600 / 700 | Smallest token, pills, badges, tags, footnotes | +| Role | Token | Size | Family | Weight | Notes | +| ---------------- | ----------------- | -------------------------------- | ------------------ | --------- | ------------------------------------------------- | +| Hero headline | (literal `clamp`) | `clamp(4.5rem, 11vw, 8.5rem)` | Cormorant Garamond | 600 | Magazine-cover scale, single use on the hero | +| Page title | `--display-lg` | `clamp(3.6rem, 9vw, 7rem)` | Cormorant Garamond | 600 | Category and sponsorship `h1` | +| Section heading | `--display-md` | `clamp(2.25rem, 4.2vw, 3.3rem)` | Cormorant Garamond | 600 | Guide, results, CTA `h2`, sponsor name | +| Display small | `--display-sm` | `clamp(1.75rem, 2.8vw, 2.25rem)` | Cormorant Garamond | 600 | Group-row `h2`, past sponsor names | +| Lede | `--text-2xl` | `1.5rem` | Manrope | 400 | Category intro first paragraph, sponsorship ledes | +| Subtitle | `--text-xl` | `1.25rem` | Manrope | 400 | Hero and category subtitles, category intro | +| Body large | `--text-lg` | `1.125rem` | Manrope | 400 | Content-heavy passages, project names, search | +| Body | `--text-base` | `1rem` (16px) | Manrope | 400 | Body floor | +| Meta / secondary | `--text-sm` | `0.95rem` | Manrope | 400 / 600 | Meta rows, secondary copy | +| Caption / pill | `--text-xs` | `0.8rem` (12.8px) | Manrope | 600 / 700 | Smallest token, pills, badges, tags, footnotes | Hard-won sizing rules (do not relax): +- **Every `font-size` uses a scale token.** The literal exceptions are the hero headline, `.tier-amount`, the sort `.arrow` glyph, and `em` sizes on inline code and `kbd`. Body tokens are fixed `rem`; only display tokens are fluid, because `vw` in body text does not grow with browser zoom. Round a new size up to the next token instead of adding an in-between step: sizes 1 to 2px apart read as noise, not hierarchy. - **Body type floor is 16px.** Do not go smaller. - **Absolute minimum font size is 12px (`0.75rem`) for ANY text**, including pills, badges, tags, captions, footnotes. Anything smaller hits Chrome's default minimum-font-size floor and renders inconsistently across browsers and user accessibility settings. - **When in doubt, pick one step larger** than what generic scale references suggest (`--text-base` over `--text-sm`, 1.75rem over 1.5rem for a heading). The maintainer has corrected sizes upward 11+ times across 8 sessions. Footer, meta rows, expand content, labels, and headings all trend too small by default. **Never reduce an existing size unprompted.** - Adjacent heading levels differ by at least 0.25rem of rendered size. - Row numbers in the table: left-align, no leading zeros. Zero-padding was tried and rejected. +- **Cormorant Garamond numerals use lining figures** (`font-variant-numeric: lining-nums`). Its default old-style figures shrink zeros to x-height and drop 3/4/5/7/9 below the baseline, so a price like `$500` reads as `$5oo`. - **Never `text-transform`.** Write the casing in the markup. ## Layout @@ -136,7 +146,7 @@ Hard-won sizing rules (do not relax): Depth comes from **tonal layers**, not heavy shadows. -- The page is a quiet warm canvas (`--bg-page`). The content shell is slightly brighter paper (`--bg-paper`). The sponsor band, CTA backgrounds, and inline decorative blocks step up to `--bg-paper-strong`. +- The page is a quiet warm canvas (`--bg-page`). The content shell is slightly brighter paper (`--bg-paper`). CTA backgrounds and inline decorative blocks step up to `--bg-paper-strong`; the sponsor band steps further, to `--sponsor-bg`. - The hero and the category guide band are the only places with real atmosphere: warm gradients on a dark earthy ground (`--hero-bg-start` → `--hero-bg-mid` → `--hero-bg-end`). Only the hero adds the subtle grid and slow sheen. The sheen and any other motion respect `prefers-reduced-motion`. - The footer is a single tonal block in `--footer-bg`, no internal gradients. - Two depth treatments are allowed and only these two. The search input combines a 1px inset highlight (`--search-inset`) with a soft warm drop shadow (`--search-shadow`, intensified by `--search-focus-shadow` on focus). The primary CTA button (`.hero-action-primary`) carries a warm drop shadow for press affordance. Both shadows are soft, warm-tinted, and tied to interactive elements. No new drop shadows on cards, panels, rows, or static decoration. @@ -162,7 +172,7 @@ The component vocabulary is small and table-led. Source of truth: `website/stati - **Hero**. Magazine-cover headline, dark earthy ground, kicker and proof microcopy, primary CTA button using `--hero-btn-start` / `--hero-btn-end`. Subtle grid plus slow sheen. Respects `prefers-reduced-motion`. - **Jump links**. One per use case in a category hero, plus one for the guide. Underlined like the intro's links, with a trailing ↓. Never tag-styled: tags filter the table or open another page, jump links only scroll. - **Guide band**. Everything in a category intro after its "How to choose" list. It sits below the table on the hero's dark gradient, with its H2 above the text. -- **Sponsor band**. Sits below the hero on the home page and category pages, on `--bg-paper-strong`. Editorial layout, not a logo wall. Sponsor links share the global accent treatment. +- **Sponsor band**. Sits below the hero on the home page and category pages, on `--sponsor-bg` with a `--line-strong` bottom border. Editorial layout, not a logo wall. Sponsor links share the global accent treatment; each sponsor name ends in a small ↗ in `--accent-deep` to mark it as an outbound link. - **CTA**. Warm `--cta-bg`, full-bleed within shell. The button itself uses accent tokens. - **Footer**. Dark warm charcoal, part of the same system. Footer links share the global hover and focus treatment. - **Search**. Pill input with `--search-inset` interior and `--search-focus-ring` focus ring. Focus shadow uses `--search-focus-shadow`. diff --git a/website/static/style.css b/website/static/style.css index 4e0ea619..110b995f 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -56,11 +56,18 @@ --tag-active-end: oklch(74% 0.11 58); --cta-bg: oklch(94% 0.025 72); + --sponsor-bg: oklch(91% 0.04 68); --text-xs: 0.8rem; --text-sm: 0.95rem; --text-base: 1rem; --text-lg: 1.125rem; + --text-xl: 1.25rem; + --text-2xl: 1.5rem; + + --display-sm: clamp(1.75rem, 2.8vw, 2.25rem); + --display-md: clamp(2.25rem, 4.2vw, 3.3rem); + --display-lg: clamp(3.6rem, 9vw, 7rem); --footer-bg: oklch(16% 0.025 35); --footer-text: oklch(72% 0.02 75); @@ -306,7 +313,7 @@ kbd { .hero-sub { margin-top: 2rem; color: var(--hero-muted); - font-size: clamp(1rem, 2vw, 1.18rem); + font-size: var(--text-xl); text-wrap: pretty; } @@ -347,12 +354,24 @@ kbd { } .hero-category-nav { + padding-top: 1.35rem; + border-top: 1px solid var(--hero-line); +} + +.hero-category-details { display: grid; grid-template-columns: minmax(10rem, 14rem) minmax(0, 1fr); gap: clamp(1.5rem, 4vw, 3rem); align-items: start; - padding-top: 1.35rem; - border-top: 1px solid var(--hero-line); +} + +.hero-category-meta { + display: block; + cursor: pointer; +} + +.hero-category-meta::-webkit-details-marker { + display: none; } .hero-category-meta h2 { @@ -362,6 +381,14 @@ kbd { letter-spacing: 0.04em; } +.hero-category-meta h2::after { + content: " ↓"; +} + +.hero-category-details[open] .hero-category-meta h2::after { + content: " ↑"; +} + .hero-category-links { list-style: none; display: grid; @@ -372,7 +399,7 @@ kbd { .hero-category-link { color: var(--hero-muted); - font-size: 0.72rem; + font-size: var(--text-xs); font-weight: 700; line-height: 1.35; text-decoration: underline; @@ -432,6 +459,7 @@ kbd { .hero-brand-mini:focus-visible, .hero-topbar-link:focus-visible, .hero-category-link:focus-visible, +.hero-category-meta:focus-visible, .search:focus-visible, .tag:focus-visible, .jump-link:focus-visible, @@ -463,7 +491,7 @@ kbd { .category-hero h1 { font-family: var(--font-display); - font-size: clamp(3.6rem, 9vw, 7rem); + font-size: var(--display-lg); line-height: 0.9; font-weight: 600; text-wrap: balance; @@ -472,7 +500,7 @@ kbd { .category-breadcrumb { margin: 0 0 1rem; color: var(--hero-muted); - font-size: clamp(1rem, 1.5vw, 1.1rem); + font-size: var(--text-lg); } .category-breadcrumb a { @@ -487,9 +515,10 @@ kbd { } .category-subtitle { - margin-top: 1.1rem; + /* Cormorant descenders hang ~0.28em below the h1's 0.9 line box, so the gap scales with the h1. */ + margin-top: max(1.1rem, var(--display-lg) * 0.3); color: var(--hero-muted); - font-size: clamp(1rem, 1.8vw, 1.18rem); + font-size: var(--text-xl); text-wrap: pretty; } @@ -515,13 +544,13 @@ kbd { display: grid; gap: 0.9rem; color: var(--hero-muted); - font-size: clamp(1.05rem, 1.8vw, 1.2rem); + font-size: var(--text-xl); text-wrap: pretty; } .category-intro > p:first-child { color: var(--hero-text); - font-size: clamp(1.2rem, 2.2vw, 1.45rem); + font-size: var(--text-2xl); line-height: 1.45; } @@ -574,7 +603,7 @@ kbd { .guide-section h2 { font-family: var(--font-display); - font-size: clamp(2.2rem, 4vw, 3.3rem); + font-size: var(--display-md); font-weight: 600; line-height: 0.94; letter-spacing: -0.03em; @@ -597,9 +626,8 @@ kbd { .sponsor-band { padding-block: clamp(2.5rem, 5.5vw, 4rem); - background: - linear-gradient(180deg, var(--bg-paper-strong), var(--bg-paper)); - border-bottom: 1px solid var(--line); + background: var(--sponsor-bg); + border-bottom: 1px solid var(--line-strong); } .sponsor-shell { @@ -667,15 +695,25 @@ kbd { .sponsor-name { font-family: var(--font-display); - font-size: clamp(2.25rem, 4.2vw, 3.25rem); + font-size: var(--display-md); font-weight: 600; line-height: 0.95; letter-spacing: -0.025em; } +.sponsor-name::after { + content: "\2197" / ""; + margin-left: 0.25em; + font-family: var(--font-body); + font-size: 0.45em; + /* Centers the arrow on the name's cap height */ + vertical-align: 0.33em; + color: var(--accent-deep); +} + .sponsor-desc { color: var(--ink-soft); - font-size: clamp(1rem, 1.5vw, 1.1rem); + font-size: var(--text-lg); line-height: 1.55; } @@ -693,7 +731,7 @@ kbd { .results-intro h2, .final-cta h2 { font-family: var(--font-display); - font-size: clamp(2.2rem, 4vw, 3.3rem); + font-size: var(--display-md); font-weight: 600; line-height: 0.94; letter-spacing: -0.03em; @@ -750,7 +788,7 @@ kbd { border-radius: 999px; background: linear-gradient(180deg, oklch(100% 0 0 / 0.82), var(--bg-paper)); color: var(--ink); - font-size: clamp(1rem, 1.4vw, 1.06rem); + font-size: var(--text-lg); box-shadow: inset 0 1px 0 var(--search-inset), 0 1.4rem 2.6rem -2.1rem var(--search-shadow); @@ -854,7 +892,7 @@ kbd { align-items: baseline; gap: 0.75rem; font-family: var(--font-display); - font-size: clamp(1.7rem, 2.8vw, 2.2rem); + font-size: var(--display-sm); font-weight: 600; line-height: 1; scroll-margin-top: 4.5rem; @@ -896,9 +934,13 @@ kbd { background: var(--row-hover); } +.row:focus-visible { + outline: 2px solid var(--accent); + outline-offset: -2px; +} + .row:focus-visible td { background: var(--row-focus); - box-shadow: inset 3px 0 0 var(--accent); } .row:has(+ .desc-row:not([hidden])) td { @@ -927,7 +969,7 @@ kbd { .col-name > a { color: var(--ink); - font-size: clamp(1rem, 1.5vw, 1.08rem); + font-size: var(--text-lg); font-weight: 700; overflow-wrap: break-word; word-break: break-word; @@ -1163,7 +1205,7 @@ th[data-sort].sort-asc::after { } .expand-commit, -.expand-downloads { +.expand-stars { display: none; } @@ -1209,6 +1251,9 @@ th[data-sort].sort-asc::after { } .back-to-top { + /* Grows the tap target past 24px without changing the header row height */ + padding-block: 0.5rem; + margin-block: -0.5rem; border: 0; background: none; color: var(--accent-deep); @@ -1264,8 +1309,12 @@ th[data-sort].sort-asc::after { gap: clamp(2rem, 5vw, 3.5rem); } +.sponsorship-hero-copy .hero-kicker { + margin-bottom: 0.5rem; +} + .sponsorship-hero-copy h1 { - font-size: clamp(3.4rem, 8.5vw, 6.5rem); + font-size: var(--display-lg); } .sponsorship-proof { @@ -1361,11 +1410,9 @@ th[data-sort].sort-asc::after { } .sponsorship-lede { - font-family: var(--font-display); - font-size: clamp(1.55rem, 2.6vw, 2rem); - line-height: 1.25; + font-size: var(--text-2xl); + line-height: 1.45; color: var(--ink); - letter-spacing: -0.01em; text-wrap: pretty; } @@ -1385,9 +1432,9 @@ th[data-sort].sort-asc::after { } .sponsorship-facts dt { - font-size: var(--text-xs); + font-size: var(--text-sm); font-weight: 800; - letter-spacing: 0.05em; + letter-spacing: 0.04em; color: var(--ink); } @@ -1415,16 +1462,17 @@ th[data-sort].sort-asc::after { } .tier-eyebrow { - font-size: var(--text-xs); + font-size: var(--text-sm); font-weight: 800; - letter-spacing: 0.05em; + letter-spacing: 0.04em; color: var(--ink); } .tier-price { display: flex; + flex-wrap: wrap; align-items: baseline; - gap: 0.55rem; + gap: 0.35rem 0.55rem; margin-bottom: 0.25rem; } @@ -1434,6 +1482,7 @@ th[data-sort].sort-asc::after { font-weight: 600; line-height: 0.9; letter-spacing: -0.025em; + font-variant-numeric: lining-nums; color: var(--ink); } @@ -1509,15 +1558,15 @@ th[data-sort].sort-asc::after { .past-sponsors li { display: flex; - flex-wrap: wrap; - align-items: baseline; - gap: 0.65rem; + flex-direction: column; + align-items: start; + gap: 0.35rem; padding-block: 0.4rem; } .past-sponsors a { font-family: var(--font-display); - font-size: clamp(1.6rem, 2.8vw, 2.1rem); + font-size: var(--display-sm); font-weight: 600; line-height: 1; letter-spacing: -0.02em; @@ -1530,8 +1579,8 @@ th[data-sort].sort-asc::after { } .past-sponsor-desc { - color: var(--ink-muted); - font-size: var(--text-base); + color: var(--ink-soft); + font-size: var(--text-lg); } .sponsorship-cta-row { @@ -1563,7 +1612,7 @@ th[data-sort].sort-asc::after { .final-cta p { color: var(--ink-soft); - font-size: clamp(1rem, 1.6vw, 1.08rem); + font-size: var(--text-lg); } .final-cta .hero-action-primary { @@ -1704,7 +1753,7 @@ th[data-sort].sort-asc::after { gap: 0.35rem; } - .hero-category-nav { + .hero-category-details { grid-template-columns: 1fr; gap: 0.95rem; } @@ -1718,12 +1767,12 @@ th[data-sort].sort-asc::after { } .col-commit, - .col-downloads { + .col-stars { display: none; } .expand-commit, - .expand-downloads { + .expand-stars { display: inline; } @@ -1784,10 +1833,6 @@ th[data-sort].sort-asc::after { column-gap: 0.75rem; } - .hero-category-link { - font-size: 0.68rem; - } - .search { min-height: 3.5rem; border-radius: 1.25rem; @@ -1837,8 +1882,8 @@ th[data-sort].sort-asc::after { padding-right: 0.8rem; } - .col-stars { - width: 5.4rem; + .col-downloads { + width: 7.5rem; } .col-arrow { diff --git a/website/templates/category.html b/website/templates/category.html index 6b867269..e27e5f90 100644 --- a/website/templates/category.html +++ b/website/templates/category.html @@ -197,10 +197,10 @@ >{% endif %} {% if entry.downloads is not none %}{% endif %} {% if entry.stars is not none %}/{{ - "{:,}".format(entry.downloads) }} downloads/month{% endif %} diff --git a/website/templates/index.html b/website/templates/index.html index 4b024c3c..6020f35b 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -53,18 +53,26 @@ @@ -257,10 +265,10 @@ >{% endif %} {% if entry.downloads is not none %}{% endif %} {% if entry.stars is not none %}/{{ - "{:,}".format(entry.downloads) }} downloads/month{% endif %} diff --git a/website/templates/sponsorship.html b/website/templates/sponsorship.html index 46d546d8..c250a8f3 100644 --- a/website/templates/sponsorship.html +++ b/website/templates/sponsorship.html @@ -116,7 +116,7 @@

Headline Sponsor

$500 - / month or $4,500 / year + / month or $4,500 / year

Logo pinned at the top of the README. Logo on the website. @@ -139,7 +139,7 @@

Featured Sponsor

$200 - / month or $1,800 / year + / month or $1,800 / year

Small logo and text link pinned at the top of the README. Logo and @@ -166,7 +166,7 @@

Indie Dev Sponsor

$99 - / month, $249 / quarter, or $891 / year + / month, $249 / quarter, or $891 / year

Lower-cost text link for eligible indie developers and solo