An open row put about 38px between the project name and its description and 10px before its links, and category rows put 26px between name and description, because .table tbody td overrode the zero top padding meant for description and expand rows. The top gap is now about 2px larger than the bottom one, since the bold name's descenders make an equal gap look smaller.
Co-Authored-By: Claude <noreply@anthropic.com>
Each row restarted its own gradient, so the darker bottom of the open row met the lighter top of its expand row and read as a faint border between them.
Co-Authored-By: Claude <noreply@anthropic.com>
Below 960px the -1rem top margin on the sponsor link, meant for the side-by-side desktop layout, pulled the sponsor name closer to the link than the link sat to its own label, so the link read as part of the sponsor entry.
Co-Authored-By: Claude <noreply@anthropic.com>
On phones the hero stats ran together as one sentence, breaking wherever space ran out and leaving a "/" dangling at a line end.
Co-Authored-By: Claude <noreply@anthropic.com>
At phone width the two primary buttons labelled with the full address wrapped over three lines, and the address in the Get started sentence broke at its hyphen.
Co-Authored-By: Claude <noreply@anthropic.com>
On narrow phone heroes the sheen, a diagonal light stripe sliding across for 54s after load, rendered as a near-vertical band sweeping sideways that read as a loading or progress bar.
Co-Authored-By: Claude <noreply@anthropic.com>
The home hero was forced to the full viewport height, opening an empty band between the top bar and the headline whenever its content was shorter than the window and pushing the project table down.
Co-Authored-By: Claude <noreply@anthropic.com>
Sponsorship-page, sponsor band, category, group-page lead, and home hero links fell back to the browser's default focus ring.
Co-Authored-By: Claude <noreply@anthropic.com>
The sponsor band's background faded from --bg-paper-strong to --bg-paper, ending lighter than the page below it, with only a faint bottom border, so the band blended into the search section and read as its intro rather than a sponsor placement; the sponsor name also gave no cue that it links out.
Co-Authored-By: Claude <noreply@anthropic.com>
The longer billing lines added with the annual prices broke across two or three lines beside the price and split amounts from their units.
Co-Authored-By: Claude <noreply@anthropic.com>
On phones the hero's 74-link category grid was 1,236px tall and pushed the project table down to 2,583px, over three screens.
Co-Authored-By: Claude <noreply@anthropic.com>
Below 960px the table hid the PyPI Downloads column but kept the default downloads sort, so the visible Stars column looked unsorted and the active sort header was not shown or tappable.
Co-Authored-By: Claude <noreply@anthropic.com>
Keyboard focus on a table row drew one box per cell, because the focused row fell back to the browser's default outline and each cell also got an inset accent stripe on its left edge.
Co-Authored-By: Claude <noreply@anthropic.com>
The sponsorship hero kicker sat farther above the heading than the heading sat above its subtitle, so the label read as detached from the heading it labels.
Co-Authored-By: Claude <noreply@anthropic.com>
The subtitle's fixed top margin did not grow with the fluid h1, so heading descenders crowded the subtitle on category and sponsorship heroes.
Co-Authored-By: Claude <noreply@anthropic.com>
The sponsorship ledes were set in Cormorant Garamond, whose short x-height and thin strokes read poorly across a paragraph, and past sponsor names shared a baseline with Manrope descriptions, where the mismatched x-heights clash.
Co-Authored-By: Claude <noreply@anthropic.com>
On the sponsorship page the tier names and fact labels rendered smaller than the "/ month" cadence beneath them, inverting the hierarchy.
Co-Authored-By: Claude <noreply@anthropic.com>
Roughly 20 ad-hoc font-size values rendered near-duplicate sizes 1-2px apart, reading as noise rather than hierarchy, and .hero-category-link rendered below the documented 12px floor.
Co-Authored-By: Claude <noreply@anthropic.com>
Sponsorship tier prices rendered in Cormorant Garamond's default old-style figures, so zeros sat at x-height and the 5 dropped below the baseline, making "$500" hard to read.
Co-Authored-By: Claude <noreply@anthropic.com>
Mailto clicks on the sponsorship page leave no page view, so the sponsor funnel ended at the sponsorship page and never showed who went on to email. Each click now sends a sponsor_contact event with a short tier value (headline, featured, indie, or general) rather than the link URL, since GA4 caps event parameter values at 100 characters and the Indie Dev mailto href is 101.
Co-Authored-By: Claude <noreply@anthropic.com>
Picks in a "How to choose" list were plain text, so a reader had to hunt for the tool's row in the table.
Co-Authored-By: Claude <noreply@anthropic.com>
The hero-rise fade-in started .hero-copy, which holds the LCP <h1>, at opacity 0, and Chrome ignores opacity-0 paints for LCP, delaying it by about 455 ms.
Co-Authored-By: Claude <noreply@anthropic.com>
`.results-note` carried an inner `max-width: 28rem`, which breaks the rule that `.section-shell` is the only width cap.
Co-Authored-By: Claude <noreply@anthropic.com>
Group pages showed only tables, so visitors arriving from broad searches like "python ml library" got none of the which-one-to-pick guidance that each section's intro already gives.
Co-Authored-By: Claude <noreply@anthropic.com>
Inline code in category intros and guides inherited the body font with no background, so identifiers like INSTALLED_APPS read as ordinary words.
Co-Authored-By: Claude <noreply@anthropic.com>
applyFilters walked the static load-order NodeList, so after sorting by a column header, row numbers kept each row's original load-order position instead of counting 1..n down the sorted table.
Co-Authored-By: Claude <noreply@anthropic.com>
On section and subcategory pages, every row repeated its use case and current page as tags (and as the label under the name on phones), right under a heading that already said the same thing. They are now hidden in editorial order and shown again when a column sort flattens the groups.
Co-Authored-By: Claude <noreply@anthropic.com>
After sorting by a column, or while a search hid a group, category page group headings stayed hidden, so the header's jump links (and any use-case heading link) pointed at a hidden element and did nothing.
Co-Authored-By: Claude <noreply@anthropic.com>
Clicking a category or group tag filtered the homepage table in place while rewriting the address bar to the category URL, so one URL rendered two different pages and readers never reached category pages with their intros and guides; category pages also showed a redundant self-referential filter bar.
Co-Authored-By: Claude <noreply@anthropic.com>
Category pages sorted rows by downloads, which buried editorial leads (the Django ORM showed as row 7 of 7, tkinter as 14 of 14) against CONTRIBUTING.md's "position is the marker"; the full intro in the hero pushed the table 2.5 screens down on a phone; and every page repeated the same "Search every project in one place" H2.
Co-Authored-By: Claude <noreply@anthropic.com>
Category pages carried no text of their own beyond the README one-line description, and most meta descriptions fell back to a generic "Explore N curated Python projects" line, which correlated with weak search rankings for category queries. This adds optional per-category intro markdown files rendered under the H1, with the first paragraph used as the meta description and links opening in a new tab, starting with the ORM category.
Co-Authored-By: Claude <noreply@anthropic.com>
Kicker now mirrors the hero kicker ("The definitive list that
answers..."), replacing the old "field guide" line changed in
8b14b4f. Subtitle now matches the current tagline ("An opinionated
guide to the best Python frameworks, libraries, and tools.") on one
line. PNG regenerated from the SVG.
Co-Authored-By: Claude <noreply@anthropic.com>
Entries with a download count now sort first (descending), with
stars, then Built-in, then name as fallback tiers for entries that
lack a count. main.js mirrors this in its default activeSort, clean
URL check, and third-click reset target. Sorting by stars remains one
header click away.
Co-Authored-By: Claude <noreply@anthropic.com>
Sourced from website/data/pypi_downloads.tsv the same way
github_stars.json feeds the stars column. The new sortable column
sits between GitHub Stars and Last Commit on the homepage and
category pages, formatted with thousands separators like stars, with
an em dash when no PyPI data exists. Rows are matched by normalized
README display name; Built-in entries never show counts since
same-named PyPI packages are stdlib backports (e.g. the asyncio
package).
Below 960px the column hides and the count moves into the expand
row, mirroring the existing Last Commit treatment. main.js gains the
downloads sort branch and URL param.
The deploy workflow fetches the TSV via the new
make fetch_pypi_downloads target with a daily actions/cache
fallback, mirroring the stars fetch, but non-fatal: the column
degrades to dashes when the fetch fails, unlike stars which the
build requires.
Co-Authored-By: Claude <noreply@anthropic.com>
On category pages desc-rows are always visible. On the index page they
were always hidden. Now they become visible whenever a tag/category
filter is applied, giving filtered results the same richness as category
pages.
Also tightens two related CSS rules: border-bottom suppression only
fires when the adjacent desc-row is actually visible, and the expand-row
description is hidden while the desc-row is already showing to avoid
duplicate text.
Co-Authored-By: Claude <noreply@anthropic.com>