balackburn/apollo
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
3 files reviewed·August 3, 2026
More findings
Verdict
Polished surface, brittle plumbing: nice CTA hierarchy and lightbox labeling sit on top of a page that can go fully invisible if one script fails. Fix the reveal dependency first, everything else is secondary until content reliably renders.
Files Rams reviewed
src/style.css
public/google8d430bc7a2b05024.html
index.html
Accessibility
src/style.css:168
Entire page ships invisible by default if the reveal script fails
Nearly every content block in the page (".hero-title", ".hero-desc", ".carousel-item", ".features-heading", ".feature-row", ".quote-text", ".footer-grid", and more) is set to opacity: 0 in style.css with no fallback rule. Visibility depends entirely on a JS-driven reveal-on-scroll script adding a class or animation later. There is no <noscript> override and no no-JS class guard anywhere in the CSS.
Why it matters
If the reveal script errors, is blocked by an extension, or simply hasn't fired yet on slow connections, the hero, features, testimonial, and footer are permanently blank for that visitor. A single script failure takes down the entire page's content, not just an animation.
Fix
Add a no-JS fallback selector that forces opacity: 1 on all reveal targets when JavaScript hasn't executed.
.hero-glow, .hero-title, .hero-desc, .hero-note, .hero-actions,
.carousel-header, .carousel-item,
.features-label, .features-heading, .features-sub, .feature-row,
.quote-mark, .quote-text, .quote-cite,
.footer-grid, .footer-watermark { opacity: 0; }.hero-glow, .hero-title, .hero-desc, .hero-note, .hero-actions,
.carousel-header, .carousel-item,
.features-label, .features-heading, .features-sub, .feature-row,
.quote-mark, .quote-text, .quote-cite,
.footer-grid, .footer-watermark { opacity: 0; }
html.no-js .hero-glow, html.no-js .hero-title, html.no-js .hero-desc, html.no-js .hero-note, html.no-js .hero-actions,
html.no-js .carousel-header, html.no-js .carousel-item,
html.no-js .features-label, html.no-js .features-heading, html.no-js .features-sub, html.no-js .feature-row,
html.no-js .quote-mark, html.no-js .quote-text, html.no-js .quote-cite,
html.no-js .footer-grid, html.no-js .footer-watermark { opacity: 1; }index.html:30
Install dropdown gives screen reader users no open/closed state
The "Install" trigger button and its four nested group toggles ("Standard Source", "No Extensions", and the others inside #install-dropdown) are plain <button> elements with no aria-haspopup, aria-expanded, or aria-controls, and the menu container itself has no role="menu". The menu is shown/hidden purely via inline style="display:none" toggled by JS.
Why it matters
A screen reader user hears "Install, button" with no indication that activating it opens a submenu, and no announcement when it opens or closes. The same applies to each nested group toggle, so a keyboard user can't tell which source group is currently expanded without visually scanning the page.
Fix
Expose disclosure state with aria-haspopup, aria-expanded, and aria-controls on every toggle, and mark the menu container with role="menu".
<button id="install-trigger" class="btn btn-primary">
Install
</button>
<div id="install-dropdown" class="dropdown-menu" style="display:none;">
<div class="dropdown-group">
<button class="dropdown-group-title">Standard Source ...</button><button id="install-trigger" class="btn btn-primary" aria-haspopup="true" aria-expanded="false" aria-controls="install-dropdown">
Install
</button>
<div id="install-dropdown" class="dropdown-menu" role="menu" style="display:none;">
<div class="dropdown-group">
<button class="dropdown-group-title" aria-expanded="false" aria-controls="standard-source-items">Standard Source ...</button>Typography
src/style.css:6
Two blocking font @imports delay every visible text render
style.css opens with @import url('https://fonts.googleapis.com/...') and @import url('https://api.fontshare.com/...') for Geist, Geist Mono, and Switzer. CSS @import is render-blocking: the browser must fetch and parse each imported stylesheet sequentially before the rest of style.css (and therefore the page) can paint.
Why it matters
Every visitor pays two extra cross-origin round trips before "Apollo for Reddit" and the hero copy render in their intended face, adding to time-to-first-paint on every load, not just cold cache.
Fix
Replace CSS @import with <link rel="preconnect"> and <link rel="stylesheet"> tags in the HTML head so font fetches happen in parallel with CSS parsing instead of blocking it.
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@500&display=swap');
@import url('https://api.fontshare.com/v2/css?f[]=switzer@500,600&display=swap');/* Move these to <link rel="preconnect"> + <link rel="stylesheet"> in <head> instead of @import, which serializes the fetch behind CSS parsing */Get this score on every PR.
Rams reviews each pull request on your repo and posts inline one-click fixes — about a minute per review.
Install Rams freeComponents
src/style.css:148
Lightbox close button sits below the mobile touch target minimum
".lightbox-close" is defined at width: 36px; height: 36px, a circular icon-only button positioned absolute in the top-right corner of the image lightbox.
Why it matters
36px falls under the 44x44px minimum touch target guideline, so on a phone the close control is harder to hit precisely, especially with the surrounding blurred overlay reducing visual contrast around the tap zone.
Fix
Size icon-only touch targets to at least 44x44px.
.lightbox-close {
position: absolute; top: 20px; right: 20px;
width: 36px; height: 36px; border-radius: 50%;
background: rgba(255,255,255,0.08); color: var(--text-50);
display: flex; align-items: center; justify-content: center;
font-size: 18px; transition: background 0.15s, color 0.15s;
}.lightbox-close {
position: absolute; top: 20px; right: 20px;
width: 44px; height: 44px; border-radius: 50%;
background: rgba(255,255,255,0.08); color: var(--text-50);
display: flex; align-items: center; justify-content: center;
font-size: 18px; transition: background 0.15s, color 0.15s;
}Color
Spacing
Motion
UX
Craft
Working well
- The hero CTA row differentiates hierarchy correctly: "Install" is a filled btn-primary while the surrounding actions use btn-ghost, so the eye lands on the primary action first without needing extra size or color tricks.
- Lightbox controls ("Close", "Previous", "Next") all carry explicit aria-label attributes despite being glyph-only buttons, which is the right fix for icon-only controls and something the dropdown menu should borrow.
- The prefers-reduced-motion block correctly collapses all animation and transition durations to near-zero, a real accessibility guard most projects skip entirely.
Scored August 3, 2026 with Rams Engine v0.0.4 · Engine changelog
This page is an automated design review of balackburn/apollo’s UI code: 3 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.
More design scores
Score your own repo.
Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.
Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.