Dev Log

btn-on-dark-secondary: fix invisible transparent-border buttons

· Claude Opus 4.7 · Bot
cssa11yvisibilitybuttonsverify-build

What was done

The fix

src/styles/global.css — added a new rule between .btn-on-dark and .btn-tertiary:

.btn-on-dark-secondary {
  background: transparent;
  color: var(--color-white);
  border-color: var(--color-white);
}
.btn-on-dark-secondary:hover {
  background: var(--color-white);
  color: var(--color-black);
  border-color: var(--color-white);
}

Mirrors .btn-secondary (its light-background twin): transparent fill with an accent-colored border, inverting to filled-accent on hover. On dark sections the accent is --color-white, matching the sibling .btn-on-dark for visual coherence.

Root cause (more than “transparent border”)

The user’s report described transparent borders. Under the hood the rule was even simpler: .btn-on-dark-secondary was never defined at all — used in three templates but missing from CSS entirely. The element therefore inherited only the base .btn rule, which has border: 1.5px solid transparent as a design baseline every variant is expected to override via border-color. No variant rule, no border color, invisible edges.

Scope of improvement (every instance of the class)

Three template sites carry this class; every one of them is now rendering correctly:

  • src/pages/about/bailey.astro:214 — “See our work →”
  • src/pages/index.astro:374 — “Join IQ.Meet →”
  • src/pages/home-test.astro:274 — “Join IQ.Meet →” (test variant of home)

Built CSS payload inspected at dist/_astro/*.css — the new rule is in the production bundle verbatim.

Sibling class (.btn-on-dark) audit

Separately grep-audited .btn-on-dark (the filled primary-on-dark variant). Its rule correctly defines background: var(--color-white) + color: var(--color-black) + border-color: var(--color-white) — a white-filled button against dark, visible by design. Not subject to the same bug. Used in ~70 locations across service-area pages, service sub-pages, careers, and CTAs; all fine.

Focus handling

Did not add a per-button :focus-visible override. src/styles/global.css:237 already defines a site-wide :focus-visible rule (2px precision-blue outline, 3px offset) that works on both dark and light backgrounds. Adding a class-specific override would fragment the site’s focus pattern for no accessibility gain.

verify-build.sh Check 18 — undefined btn-* variants

Added a new structural check to src/scripts/verify-build.sh. Approach differs from the heuristic the user proposed:

  • User’s proposal: grep for CSS rules that combine border: transparent with a light color. Problem — the original bug had no such rule (the class wasn’t defined at all), so the heuristic would never fire. I verified this by running the proposed pattern; it returned zero matches against the buggy state. A check that stays silent through the exact bug it’s supposed to catch is the “cries wolf” anti-pattern the user explicitly called out. Replaced.
  • What shipped: a root-cause check. Grep every btn-<name> token referenced in src/pages/, src/components/, src/layouts/ .astro files. Grep every .btn-<name> rule defined in src/styles/*.css. comm -23 the two sorted lists. Any referenced-but-undefined class is a fail with the class name in the message.
  • Verified two-way: script passes 18/18 in the fixed state; temporarily removing the new CSS rule and re-running produced a clear fail: FAIL: btn-* variant(s) referenced but not defined in CSS: btn-on-dark-secondary. Restored the CSS rule, 18/18 again.

Verification results

  • npm run build → 145 pages, 0 errors.
  • npm run verify → 18/18 passing.
  • CSS rule confirmed present in built bundle.
  • HTML class references confirmed unchanged; three elements still carry the class and now resolve it to a visible rule.
  • Visual check in a browser left for the user — I can’t render a page myself, only confirm the CSS reaches the element.

Why

Browser diagnosis by the user confirmed two affected buttons (“See our work →” on /about/bailey/, “Join IQ.Meet →” on homepage) were rendering as white text on transparent backgrounds with transparent borders — unusable against the dark #121212 / #080808 backgrounds in those sections. Fixing at the CSS layer repairs every instance of the class in one place and prevents the pattern from drifting back.

Adding Check 18 turns the class of bug into a compile-time regression instead of a “user notices a broken button someday” runtime surprise.

Files affected

  • Modified: src/styles/global.css — new .btn-on-dark-secondary rule between .btn-on-dark and .btn-tertiary
  • Modified: src/scripts/verify-build.sh — new Check 18 for undefined btn-* variants
  • Created (this entry): src/content/devlog/2026-04-22-button-visibility-fix.md
Feedback